diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 5f4bc4a8a..1d3389b09 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 @@ -6,6 +8,18 @@ plugins { repositories { jcenter() gradlePluginPortal() + maven { + 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 { @@ -19,10 +33,24 @@ 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") 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.143") + implementation("net.fabricmc:fabric-loom:$loomVersion") + implementation("net.fabricmc:sponge-mixin:$mixinVersion") } 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/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 0ec4b175d..d1b42cac8 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/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index dc8dace40..bc0081b37 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -44,12 +44,21 @@ + + + + + + + + + @@ -63,6 +72,18 @@ + + + + + + + + + + + + diff --git a/contrib/craftscripts/README.txt b/contrib/craftscripts/README.txt index 61dd01128..c44072d8f 100644 --- a/contrib/craftscripts/README.txt +++ b/contrib/craftscripts/README.txt @@ -11,4 +11,4 @@ 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 -https://worldedit.enginehub.org/en/latest/usage/other/craftscripts/ +https://worldedit.enginehub.org/en/latest/usage/other/craftscripts/ \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 911076493..15c5a2370 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,4 +6,4 @@ org.gradle.jvmargs=-Xmx4g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError org.gradle.daemon=true org.gradle.configureondemand=true org.gradle.parallel=true -org.gradle.caching=true \ No newline at end of file +org.gradle.caching=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 0d4a95168..5c2d1cf01 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradlew b/gradlew index cccdd3d51..83f2acfdc 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" @@ -109,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"` 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-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index d54a9c986..c0f66fd83 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 @@ -31,6 +31,7 @@ import com.sk89q.worldedit.bukkit.adapter.IBukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.SimpleBukkitAdapter; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.extension.platform.PlayerProxy; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -51,15 +52,431 @@ import com.sk89q.worldedit.world.item.ItemTypes; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import java.util.Objects; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; + +import java.util.EnumMap; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +/** + * Adapts between Bukkit and WorldEdit equivalent objects. + */ +public class BukkitAdapter { + + private BukkitAdapter() { + } + + private static final ParserContext TO_BLOCK_CONTEXT = new ParserContext(); + + static { + TO_BLOCK_CONTEXT.setRestricted(false); + } + + /** + * Checks equality between a WorldEdit BlockType and a Bukkit Material + * + * @param blockType The WorldEdit BlockType + * @param type The Bukkit Material + * @return If they are equal + */ + public static boolean equals(BlockType blockType, Material type) { + return Objects.equals(blockType.getId(), type.getKey().toString()); + } + + /** + * Convert any WorldEdit world into an equivalent wrapped Bukkit world. + * + *

If a matching world cannot be found, a {@link RuntimeException} + * will be thrown.

+ * + * @param world the world + * @return a wrapped Bukkit world + */ + public static BukkitWorld asBukkitWorld(World world) { + if (world instanceof BukkitWorld) { + return (BukkitWorld) world; + } else { + BukkitWorld bukkitWorld = WorldEditPlugin.getInstance().getInternalPlatform().matchWorld(world); + if (bukkitWorld == null) { + throw new RuntimeException("World '" + world.getName() + "' has no matching version in Bukkit"); + } + return bukkitWorld; + } + } + + /** + * Create a WorldEdit world from a Bukkit world. + * + * @param world the Bukkit world + * @return a WorldEdit world + */ + public static World adapt(org.bukkit.World world) { + checkNotNull(world); + return new BukkitWorld(world); + } + + /** + * Create a WorldEdit Player from a Bukkit Player. + * + * @param player The Bukkit player + * @return The WorldEdit player + */ + public static BukkitPlayer adapt(Player player) { + return WorldEditPlugin.getInstance().wrapPlayer(player); + } + + /** + * Create a Bukkit Player from a WorldEdit Player. + * + * @param player The WorldEdit player + * @return The Bukkit player + */ + public static Player adapt(com.sk89q.worldedit.entity.Player player) { + return ((BukkitPlayer) player).getPlayer(); + } + + /** + * Create a Bukkit world from a WorldEdit world. + * + * @param world the WorldEdit world + * @return a Bukkit world + */ + public static org.bukkit.World adapt(World world) { + checkNotNull(world); + if (world instanceof BukkitWorld) { + return ((BukkitWorld) world).getWorld(); + } else { + org.bukkit.World match = Bukkit.getServer().getWorld(world.getName()); + if (match != null) { + return match; + } else { + throw new IllegalArgumentException("Can't find a Bukkit world for " + world.getName()); + } + } + } + + /** + * Create a WorldEdit location from a Bukkit location. + * + * @param location the Bukkit location + * @return a WorldEdit location + */ + public static Location adapt(org.bukkit.Location location) { + checkNotNull(location); + Vector3 position = asVector(location); + return new com.sk89q.worldedit.util.Location( + adapt(location.getWorld()), + position, + location.getYaw(), + location.getPitch()); + } + + /** + * Create a Bukkit location from a WorldEdit location. + * + * @param location the WorldEdit location + * @return a Bukkit location + */ + public static org.bukkit.Location adapt(Location location) { + checkNotNull(location); + Vector3 position = location.toVector(); + return new org.bukkit.Location( + adapt((World) location.getExtent()), + position.getX(), position.getY(), position.getZ(), + location.getYaw(), + location.getPitch()); + } + + /** + * Create a Bukkit location from a WorldEdit position with a Bukkit world. + * + * @param world the Bukkit world + * @param position the WorldEdit position + * @return a Bukkit location + */ + public static org.bukkit.Location adapt(org.bukkit.World world, Vector3 position) { + checkNotNull(world); + checkNotNull(position); + return new org.bukkit.Location( + world, + position.getX(), position.getY(), position.getZ()); + } + + /** + * Create a Bukkit location from a WorldEdit position with a Bukkit world. + * + * @param world the Bukkit world + * @param position the WorldEdit position + * @return a Bukkit location + */ + public static org.bukkit.Location adapt(org.bukkit.World world, BlockVector3 position) { + checkNotNull(world); + checkNotNull(position); + return new org.bukkit.Location( + world, + position.getX(), position.getY(), position.getZ()); + } + + /** + * Create a Bukkit location from a WorldEdit location with a Bukkit world. + * + * @param world the Bukkit world + * @param location the WorldEdit location + * @return a Bukkit location + */ + public static org.bukkit.Location adapt(org.bukkit.World world, Location location) { + checkNotNull(world); + checkNotNull(location); + return new org.bukkit.Location( + world, + location.getX(), location.getY(), location.getZ(), + location.getYaw(), + location.getPitch()); + } + + /** + * Create a WorldEdit Vector from a Bukkit location. + * + * @param location The Bukkit location + * @return a WorldEdit vector + */ + public static Vector3 asVector(org.bukkit.Location location) { + checkNotNull(location); + return Vector3.at(location.getX(), location.getY(), location.getZ()); + } + + /** + * Create a WorldEdit BlockVector from a Bukkit location. + * + * @param location The Bukkit location + * @return a WorldEdit vector + */ + public static BlockVector3 asBlockVector(org.bukkit.Location location) { + checkNotNull(location); + return BlockVector3.at(location.getX(), location.getY(), location.getZ()); + } + + /** + * Create a WorldEdit entity from a Bukkit entity. + * + * @param entity the Bukkit entity + * @return a WorldEdit entity + */ + public static Entity adapt(org.bukkit.entity.Entity entity) { + checkNotNull(entity); + return new BukkitEntity(entity); + } + + /** + * Create a Bukkit Material form a WorldEdit ItemType + * + * @param itemType The WorldEdit ItemType + * @return The Bukkit Material + */ + public static Material adapt(ItemType itemType) { + checkNotNull(itemType); + if (!itemType.getId().startsWith("minecraft:")) { + throw new IllegalArgumentException("Bukkit only supports Minecraft items"); + } + return Material.getMaterial(itemType.getId().substring(10).toUpperCase(Locale.ROOT)); + } + + /** + * Create a Bukkit Material form a WorldEdit BlockType + * + * @param blockType The WorldEdit BlockType + * @return The Bukkit Material + */ + public static Material adapt(BlockType blockType) { + checkNotNull(blockType); + if (!blockType.getId().startsWith("minecraft:")) { + throw new IllegalArgumentException("Bukkit only supports Minecraft blocks"); + } + return Material.getMaterial(blockType.getId().substring(10).toUpperCase(Locale.ROOT)); + } + + /** + * Create a WorldEdit GameMode from a Bukkit one. + * + * @param gameMode Bukkit GameMode + * @return WorldEdit GameMode + */ + public static GameMode adapt(org.bukkit.GameMode gameMode) { + checkNotNull(gameMode); + return GameModes.get(gameMode.name().toLowerCase(Locale.ROOT)); + } + + /** + * Create a WorldEdit BiomeType from a Bukkit one. + * + * @param biome Bukkit Biome + * @return WorldEdit BiomeType + */ + public static BiomeType adapt(Biome biome) { + return BiomeTypes.get(biome.name().toLowerCase(Locale.ROOT)); + } + + public static Biome adapt(BiomeType biomeType) { + if (!biomeType.getId().startsWith("minecraft:")) { + throw new IllegalArgumentException("Bukkit only supports vanilla biomes"); + } + try { + return Biome.valueOf(biomeType.getId().substring(10).toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException e) { + return null; + } + } + + /** + * Create a WorldEdit EntityType from a Bukkit one. + * + * @param entityType Bukkit EntityType + * @return WorldEdit EntityType + */ + public static EntityType adapt(org.bukkit.entity.EntityType entityType) { + 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) { + if (!entityType.getId().startsWith("minecraft:")) { + throw new IllegalArgumentException("Bukkit only supports vanilla entities"); + } + 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); + return materialBlockTypeCache.computeIfAbsent(material, input -> BlockTypes.get(material.getKey().toString())); + } + + /** + * Converts a Material to a ItemType + * + * @param material The material + * @return The itemtype + */ + @Nullable + public static ItemType asItemType(Material material) { + checkNotNull(material); + return materialItemTypeCache.computeIfAbsent(material, input -> ItemTypes.get(material.getKey().toString())); + } + + private static Int2ObjectMap blockStateCache = new Int2ObjectOpenHashMap<>(); + private static Map blockStateStringCache = new HashMap<>(); + + /** + * Create a WorldEdit BlockState from a Bukkit BlockData + * + * @param blockData The Bukkit BlockData + * @return The WorldEdit BlockState + */ + public static BlockState adapt(BlockData blockData) { + checkNotNull(blockData); + + 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 Int2ObjectMap blockDataCache = new Int2ObjectOpenHashMap<>(); + + /** + * Create a Bukkit BlockData from a WorldEdit BlockStateHolder + * + * @param block The WorldEdit BlockStateHolder + * @return The Bukkit BlockData + */ + public static > BlockData adapt(B block) { + checkNotNull(block); + // 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(); + } + + /** + * Create a WorldEdit BlockState from a Bukkit ItemStack + * + * @param itemStack The Bukkit ItemStack + * @return The WorldEdit BlockState + */ + public static BlockState asBlockState(ItemStack itemStack) throws WorldEditException { + checkNotNull(itemStack); + if (itemStack.getType().isBlock()) { + return adapt(itemStack.getType().createBlockData()); + } else { + throw new NotABlockException(); + } + } + + /** + * Create a WorldEdit BaseItemStack from a Bukkit ItemStack + * + * @param itemStack The Bukkit ItemStack + * @return The WorldEdit BaseItemStack + */ + 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()); + } + + /** + * Create a Bukkit ItemStack from a WorldEdit BaseItemStack + * + * @param item The WorldEdit BaseItemStack + * @return The Bukkit ItemStack + */ + 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()); + } +} + /** * Adapts between Bukkit and WorldEdit equivalent objects. */ 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/BukkitBlockRegistry.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java index 0736ee066..d290fb96e 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 @@ -75,6 +75,13 @@ public class BukkitBlockRegistry extends BundledBlockRegistry { return super.getMaterial(state); } + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) { + return WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(state); + } + return OptionalInt.empty(); + } @Nullable @Override public Map> getProperties(BlockType blockType) { @@ -137,9 +144,4 @@ public class BukkitBlockRegistry extends BundledBlockRegistry { } return blocks; } - - @Override - public OptionalInt getInternalBlockStateId(BlockState state) { - return WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(state); - } } 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 ffb0037d5..f1422b95c 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 @@ -106,10 +106,6 @@ public class BukkitCommandSender extends AbstractNonPlayerActor { return true; } - @Override public boolean togglePermission(String permission) { - return false; - } - @Override public void setPermission(String permission, boolean value) { } 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/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index dfb1678fd..0cd61ca33 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,8 @@ import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.Locale; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; @@ -59,7 +61,6 @@ import org.bukkit.inventory.PlayerInventory; import javax.annotation.Nullable; import java.util.HashMap; -import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -215,12 +216,12 @@ public class BukkitPlayer extends AbstractPlayerActor { @Override public GameMode getGameMode() { - return GameModes.get(getPlayer().getGameMode().name().toLowerCase(Locale.ROOT)); + return GameModes.get(player.getGameMode().name().toLowerCase(Locale.ROOT)); } @Override public void setGameMode(GameMode gameMode) { - getPlayer().setGameMode(org.bukkit.GameMode.valueOf(gameMode.getId().toUpperCase(Locale.ROOT))); + player.setGameMode(org.bukkit.GameMode.valueOf(gameMode.getId().toUpperCase(Locale.ROOT))); } @Override @@ -239,6 +240,16 @@ public class BukkitPlayer extends AbstractPlayerActor { } } + @Override + public boolean isAllowedToFly() { + return player.getAllowFlight(); + } + + @Override + public void setFlying(boolean flying) { + player.setFlying(flying); + } + @Override public void setPermission(String permission, boolean value) { /* @@ -281,16 +292,6 @@ public class BukkitPlayer extends AbstractPlayerActor { return player; } - @Override - public boolean isAllowedToFly() { - return getPlayer().getAllowFlight(); - } - - @Override - public void setFlying(boolean flying) { - getPlayer().setFlying(flying); - } - @Override public BaseEntity getState() { throw new UnsupportedOperationException("Cannot create a state from this object"); 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 82888e308..d20d04da6 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 @@ -41,8 +41,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.annotation.Nullable; import org.bukkit.Bukkit; +import javax.annotation.Nullable; import org.bukkit.Server; import org.bukkit.World; import org.bukkit.entity.EntityType; 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 0fc65b847..eac42c71c 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 @@ -34,6 +34,7 @@ import com.sk89q.jnbt.CompoundTag; 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; @@ -43,6 +44,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; @@ -328,19 +330,27 @@ public class BukkitWorld extends AbstractWorld { @Override public void checkLoadedChunk(BlockVector3 pt) { World world = getWorld(); - int X = pt.getBlockX() >> 4; - int Z = pt.getBlockZ() >> 4; - if (Fawe.isMainThread()) { - world.getChunkAt(X, Z); - } else if (!world.isChunkLoaded(X, Z)) { - if (PaperLib.isPaper()) { - world.getChunkAtAsync(X, Z, true); - } else { - Fawe.get().getQueueHandler().sync(() -> { - world.getChunkAt(X, Z); - }); - } + + world.getChunkAt(pt.getBlockX() >> 4, pt.getBlockZ() >> 4); + + if (!world.isChunkLoaded(pt.getBlockX() >> 4, pt.getBlockZ() >> 4)) { + world.loadChunk(pt.getBlockX() >> 4, pt.getBlockZ() >> 4); } + if (!world.isChunkLoaded(pt.getBlockX() >> 4, pt.getBlockZ() >> 4)) { + int X = pt.getBlockX() >> 4; + int Z = pt.getBlockZ() >> 4; + if (Fawe.isMainThread()) { + world.getChunkAt(X, Z); + } else if (!world.isChunkLoaded(X, Z)) { + if (PaperLib.isPaper()) { + world.getChunkAtAsync(X, Z, true); + } else { + Fawe.get().getQueueHandler().sync(() -> { + world.getChunkAt(X, Z); + }); + } + } + } } @Override @@ -552,4 +562,14 @@ public class BukkitWorld extends AbstractWorld { org.bukkit.entity.Player bukkitPlayer = BukkitAdapter.adapt(player); WorldEditPlugin.getInstance().getBukkitImplAdapter().sendFakeChunk(getWorld(), bukkitPlayer, packet); } + + @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; + } } 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 d7d97f8c0..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 @@ -26,7 +26,6 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; -import java.util.Optional; import org.bukkit.block.Block; import org.bukkit.event.Event.Result; import org.bukkit.event.EventHandler; @@ -42,6 +41,8 @@ import org.enginehub.piston.inject.InjectedValueStore; import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.MapBackedValueStore; +import java.util.Optional; + /** * Handles all events thrown in relation to a Player */ 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 1273e17c0..572a7fe4a 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 @@ -183,8 +183,8 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter if (Files.exists(delChunks)) { ChunkDeleter.runFromFile(delChunks, true); } - - fail(() -> PermissionsResolverManager.initialize(INSTANCE), "Failed to initialize permissions resolver"); + + fail(() -> PermissionsResolverManager.initialize(INSTANCE), "Failed to initialize permissions resolver"); } /** @@ -341,6 +341,20 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter } } + @Override + public List onTabComplete(CommandSender sender, Command cmd, String commandLabel, String[] args) { + // Add the command to the array because the underlying command handling + // code of WorldEdit expects it + String[] split = new String[args.length + 1]; + System.arraycopy(args, 0, split, 1, args.length); + split[0] = "/" + commandLabel; + + String arguments = Joiner.on(" ").join(split); + CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), arguments); + getWorldEdit().getEventBus().post(event); + return CommandUtil.fixSuggestions(arguments, event.getSuggestions()); + } + private void fail(Runnable run, String message) { try { run.run(); diff --git a/worldedit-bukkit/src/main/resources/defaults/config-legacy.yml b/worldedit-bukkit/src/main/resources/defaults/config-legacy.yml index ef7a2e6ad..524a2a8e8 100644 --- a/worldedit-bukkit/src/main/resources/defaults/config-legacy.yml +++ b/worldedit-bukkit/src/main/resources/defaults/config-legacy.yml @@ -90,3 +90,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-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar new file mode 100644 index 000000000..43a6d5009 Binary files /dev/null and b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar differ diff --git a/worldedit-cli/build.gradle.kts b/worldedit-cli/build.gradle.kts new file mode 100644 index 000000000..ab563127c --- /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(dependency("org.apache.logging.log4j:log4j-core")) + } +} + +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..970c11df5 --- /dev/null +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLICommandSender.java @@ -0,0 +1,165 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * 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.WorldEditText; +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(WorldEditText.format(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-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/OperatorToken.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIConfiguration.java similarity index 66% rename from worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/OperatorToken.java rename to worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIConfiguration.java index c4b70e475..95adb23aa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/OperatorToken.java +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIConfiguration.java @@ -17,28 +17,24 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.internal.expression.lexer.tokens; +package com.sk89q.worldedit.cli; -/** - * A unary or binary operator. - */ -public class OperatorToken extends Token { +import com.sk89q.worldedit.util.PropertiesConfiguration; - public final String operator; +import java.io.File; - public OperatorToken(int position, String operator) { - super(position); - this.operator = operator; +public class CLIConfiguration extends PropertiesConfiguration { + + public CLIConfiguration(CLIWorldEdit app) { + super(app.getWorkingDir().resolve("worldedit.properties").toFile()); } @Override - public char id() { - return 'o'; + protected void loadExtra() { } @Override - public String toString() { - return "OperatorToken(" + operator + ")"; + public File getWorkingDirectory() { + return CLIWorldEdit.inst.getWorkingDir().toFile(); } - -} +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/CharacterToken.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIItemCategoryRegistry.java similarity index 61% rename from worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/CharacterToken.java rename to worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIItemCategoryRegistry.java index 51bf757da..40b99b59a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/CharacterToken.java +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIItemCategoryRegistry.java @@ -17,28 +17,20 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.internal.expression.lexer.tokens; +package com.sk89q.worldedit.cli; -/** - * A single character that doesn't fit any of the other token categories. - */ -public class CharacterToken extends Token { +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; - public final char character; +import java.util.Set; +import java.util.stream.Collectors; - public CharacterToken(int position, char character) { - super(position); - this.character = character; - } +public class CLIItemCategoryRegistry implements ItemCategoryRegistry { @Override - public char id() { - return character; + public Set getCategorisedByName(String category) { + return CLIWorldEdit.inst.getFileRegistries().getDataFile().itemtags.get(category).stream() + .map(ItemType.REGISTRY::get) + .collect(Collectors.toSet()); } - - @Override - public String toString() { - return "CharacterToken(" + character + ")"; - } - } 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-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/KeywordToken.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorld.java similarity index 65% rename from worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/KeywordToken.java rename to worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorld.java index 208e7280c..7df65f333 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/KeywordToken.java +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorld.java @@ -17,28 +17,28 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.internal.expression.lexer.tokens; +package com.sk89q.worldedit.cli; -/** - * A keyword. - */ -public class KeywordToken extends Token { +public interface CLIWorld { - public final String value; + /** + * Saves this world back to file if dirty or forced. + * + * @param force Force a save + */ + void save(boolean force); - public KeywordToken(int position, String value) { - super(position); - this.value = value; - } - - @Override - public char id() { - return 'k'; - } - - @Override - public String toString() { - return "KeywordToken(" + value + ")"; - } + /** + * 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..5e1a26b96 --- /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 List getEntities(Region region) { + return clipboard.getEntities(region); + } + + @Override + public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) + throws MaxChangedBlocksException { + return false; + } + + @Override + public List getEntities() { + return clipboard.getEntities(); + } + + @Override + public BlockVector3 getSpawnPosition() { + return clipboard.getOrigin(); + } + + @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/build.gradle.kts b/worldedit-core/build.gradle.kts index c9f525ffb..f134bf1f0 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -21,14 +21,14 @@ configurations.all { dependencies { "compile"(project(":worldedit-libs:core")) "compile"("de.schlichtherle:truezip:6.8.3") - "compile"("rhino:js:1.7R2") + "compile"("rhino:js:1.7.11") "compile"("org.yaml:snakeyaml:1.23") "compile"("com.google.guava:guava:21.0") "compile"("com.google.code.findbugs:jsr305:3.0.2") "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") - "compile"("com.googlecode.json-simple:json-simple:1.1.1") { isTransitive = false } + "compile"("com.googlecode.json-simple:json-simple:1.3.9") { isTransitive = false } "compileOnly"(project(":worldedit-libs:core:ap")) "annotationProcessor"(project(":worldedit-libs:core:ap")) // ensure this is on the classpath for the AP @@ -48,6 +48,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/doctools/build.gradle.kts b/worldedit-core/doctools/build.gradle.kts new file mode 100644 index 000000000..0fba2e7f2 --- /dev/null +++ b/worldedit-core/doctools/build.gradle.kts @@ -0,0 +1,24 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "1.3.41" + application +} + +applyCommonConfiguration() + +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")) + "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 new file mode 100644 index 000000000..931c665ba --- /dev/null +++ b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt @@ -0,0 +1,354 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * 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.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.internal.command.CommandUtil +import com.sk89q.worldedit.util.formatting.text.TextComponent +import org.enginehub.piston.Command +import org.enginehub.piston.config.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 + +class DocumentationPrinter private constructor() { + + private val nameRegex = Regex("name = \"(.+?)\"") + 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 val matchedCommands = mutableSetOf() + + 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}, looked at ${sourceFile.toAbsolutePath()}" + } + 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 + } + } + } + } + + private fun writeAllCommands() { + writeHeader() + + dumpSection("General Commands") { + yield("worldedit") + yieldAllCommandsIn() + yieldAllCommandsIn() + } + + dumpSection("Navigation Commands") { + yieldAllCommandsIn() + } + + dumpSection("Selection Commands") { + yieldAllCommandsIn() + yield("/expand") + } + + dumpSection("Region Commands") { + yieldAllCommandsIn() + } + + dumpSection("Generation Commands") { + yieldAllCommandsIn() + } + + dumpSection("Schematic and Clipboard Commands") { + yield("schematic") + yieldAllCommandsIn() + } + + dumpSection("Tool Commands") { + yield("tool") + 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() + + val missingCommands = commands.keys.filterNot { it in matchedCommands } + require(missingCommands.isEmpty()) { "Missing commands: $missingCommands" } + } + + private fun writeHeader() { + cmdOutput.appendln(""" +======== +Commands +======== + +.. contents:: + :local: + +.. 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(""" +=========== +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 `." + ``worldedit.scripting.execute.``,"Allows using the CraftScript with the given filename." +""".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 = reduceToRst(TextConfig.commandPrefixValue()) + val commands = sequence(addCommandNames).map { this.commands.getValue(it) }.toList() + matchedCommands.addAll(commands.map { it.name }) + + 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.filterIsInstance() + .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() + 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.makeRstSafe("\n") + cmdOutput.append(" ".repeat(2)) + .append(k) + .append(",") + .append('"') + .append(rstSafe) + .append('"').appendln() + } + 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 { + footer.isPresent -> append( + TextComponent.builder("\n\n").append(footer.get()) + ) + else -> this + } + } + 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 = 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``" + reduceToRst(it.textRepresentation) + "``" + yield(title to reduceToRst(it.description)) + } + }.toMap() + } + + companion object { + + /** + * Generates documentation. + */ + @JvmStatic + fun main(args: Array) { + try { + val printer = DocumentationPrinter() + + 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) { + Files.newBufferedWriter(Paths.get(file)).use { + it.write(output) + } + } + } +} 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 17a62781d..e10029a92 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 @@ -121,7 +121,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)); @@ -180,7 +179,6 @@ public class MobSpawnerBlock extends BaseBlock { this.delay = -1; } - ShortTag spawnCountTag = null; ShortTag spawnRangeTag = null; ShortTag minSpawnDelayTag = null; 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..507aa3ad0 --- /dev/null +++ b/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 @@ -0,0 +1,236 @@ +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 : ( 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 + | simpleForStatement + | breakStatement + | continueStatement + | returnStatement + | switchStatement + | expressionStatement + | emptyStatement + ) SEMI_COLON? + ; + +block : '{' statements '}' ; + +ifStatement : IF '(' condition=expression ')' trueBranch=statement ( ELSE falseBranch=statement )? ; + +whileStatement : WHILE '(' condition=expression ')' body=statement ; + +doStatement : DO body=statement WHILE '(' condition=expression ')' ; + +// C-Style for loop +forStatement + : 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 value=expression? ; + +switchStatement : SWITCH '(' target=expression ')' '{' (labels+=switchLabel ':' bodies+=statements )+ '}' ; + +switchLabel + : CASE constant=constantExpression # Case + | DEFAULT # Default + ; + +expressionStatement : expression ; + +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 + | source=ID # IdExpr + | '(' expression ')' # WrappedExpr + ; + +constantExpression : NUMBER ; + +functionCall : name=ID '(' (args+=expression ( ',' args+=expression )*)? ')' ; 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/boydti/fawe/object/random/SimplexNoise.java b/worldedit-core/src/main/java/com/boydti/fawe/object/random/SimplexNoise.java index b90152900..551adb64e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/random/SimplexNoise.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/random/SimplexNoise.java @@ -404,4 +404,4 @@ public class SimplexNoise { this.w = w; } } -} \ No newline at end of file +} 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 04ec07be8..584fd92f0 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java @@ -23,6 +23,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Locale; +import java.util.Locale; + /** * The {@code TAG_Int_Array} tag. */ 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 1771ed9a6..88b7ff4d9 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java @@ -23,6 +23,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.Locale; +import java.util.Locale; + /** * The {@code TAG_Long_Array} tag. */ 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 index 7fe54c4ae..8dd9c94ff 100644 --- 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 @@ -21,4 +21,4 @@ * 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; +package com.sk89q.minecraft.util.commands; \ No newline at end of file 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 704fe803c..b6b05dac7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -43,6 +43,8 @@ import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.extent.EditSessionEvent; import com.sk89q.worldedit.extent.AbstractDelegateExtent; +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; @@ -60,6 +62,7 @@ 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.biome.BiomeReplace; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.block.Naturalizer; @@ -94,11 +97,11 @@ 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.EvaluationException; -import com.sk89q.worldedit.internal.expression.runtime.ExpressionTimeoutException; -import com.sk89q.worldedit.internal.expression.runtime.RValue; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.MathUtils; +import com.sk89q.worldedit.internal.expression.ExpressionTimeoutException; +import com.sk89q.worldedit.internal.expression.LocalSlot.Variable; import com.sk89q.worldedit.math.MutableBlockVector2; import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.math.Vector2; @@ -319,6 +322,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { public Extent getBypassHistory() { return bypassHistory; } + private final List watchdogExtents = new ArrayList<>(2); public void setExtent(AbstractDelegateExtent extent) { new ExtentTraverser<>(getExtent()).setNext(extent); @@ -1164,6 +1168,18 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { return this.changes = visitor.getAffected(); } + /** + * Count the number of blocks of a list of types in a region. + * + * @param region the region + * @param searchBlocks the list of blocks to search + * @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); + } + /** * Remove a cuboid above the given position with a given apothem and a given height. * @@ -1182,8 +1198,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { getWorld(), // Causes clamping of Y range position.add(-apothem + 1, 0, -apothem + 1), position.add(apothem - 1, height - 1, apothem - 1)); - Pattern pattern = BlockTypes.AIR.getDefaultState(); - return setBlocks(region, pattern); + return setBlocks(region, BlockTypes.AIR.getDefaultState()); } /** @@ -1231,16 +1246,15 @@ public class EditSession extends PassthroughExtent implements 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 SingleBlockTypeMask(this, blockType); BlockVector3 adjustment = BlockVector3.ONE.multiply(apothem - 1); Region region = new CuboidRegion( getWorld(), // Causes clamping of Y range @@ -1450,7 +1464,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { * @param region the region to stack * @param dir the direction to stack * @param count the number of times to stack - * @param copyAir true to also copy air blocks + * @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 */ @@ -1485,10 +1501,13 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { * @param region the region to move * @param dir the direction * @param distance the distance to move - * @param copyAir true to copy air blocks + * @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 copyAir, boolean moveEntities, boolean copyBiomes, Pattern replacement) throws MaxChangedBlocksException { @@ -1563,7 +1582,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { /** * Drain nearby pools of water or lava, optionally removed waterlogged states from blocks. * - * @param origin the origin to drain from, which will search a 3×3 area + * @param origin the origin to drain from, which will search a 3x3 area * @param radius the radius of the removal, where a value should be 0 or greater * @param waterlogged true to make waterlogged blocks non-waterlogged as well * @return number of blocks affected @@ -1592,14 +1611,14 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { } RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1)); - // Around the origin in a 3×3 block + // Around the origin in a 3x3 block for (BlockVector3 position : CuboidRegion.fromCenter(origin, 1)) { if (mask.test(position)) { visitor.visit(position); } } - Operations.completeBlindly(visitor); + Operations.completeLegacy(visitor); return this.changes = visitor.getAffected(); } @@ -1680,6 +1699,21 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { return makeCylinder(pos, block, radiusX, radiusZ, height, thickness, false); } + /** + * 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 + * @param count the number of times to stack + * @param copyAir true to also copy air blocks + * @return number of blocks affected + * @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)); + } + private int makeCylinder(BlockVector3 pos, Pattern block, double radiusX, double radiusZ, int height, double thickness, boolean filled) throws MaxChangedBlocksException { int affected = 0; @@ -1790,6 +1824,21 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { return this.changes; } + /** + * 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 copyAir true to copy air blocks + * @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 + */ + 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); + } + public int makeCircle(BlockVector3 pos, final Pattern block, double radiusX, double radiusY, double radiusZ, boolean filled, Vector3 normal) throws MaxChangedBlocksException { radiusX += 0.5; radiusY += 0.5; @@ -2322,8 +2371,10 @@ public class EditSession extends PassthroughExtent implements 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); @@ -2371,9 +2422,12 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { final Expression expression = Expression.compile(expressionString, "x", "y", "z"); expression.optimize(); - final RValue x = expression.getVariable("x", false).optimize(); - final RValue y = expression.getVariable("y", false).optimize(); - final RValue z = expression.getVariable("z", false).optimize(); + 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/EditSessionFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionFactory.java index 5b972e577..cdf247daf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionFactory.java @@ -20,8 +20,6 @@ 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; 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 15849e7fc..c6855b4a7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -78,7 +78,6 @@ 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.snapshot.Snapshot; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import java.io.File; @@ -148,6 +147,7 @@ public class LocalSession implements TextureHolder { private transient ResettableExtent transform = null; private transient ZoneId timezone = ZoneId.systemDefault(); private transient World currentWorld; + private transient boolean tickingWatchdog = false; private transient UUID uuid; private transient volatile long historySize = 0; @@ -157,8 +157,6 @@ public class LocalSession implements TextureHolder { private transient World worldOverride; private transient boolean tickingWatchdog = false; - private transient boolean loadDefaults = true; - // Saved properties private String lastScript; private RegionSelectorType defaultSelector; @@ -1104,6 +1102,14 @@ public class LocalSession implements TextureHolder { } } + public void setPlaceAtPos1(boolean placeAtPos1) { + this.placeAtPos1 = placeAtPos1; + } + + public boolean isPlaceAtPos1() { + return placeAtPos1; + } + public void setTool(BaseItem item, @Nullable Tool tool, Player player) throws InvalidToolBindException { ItemType type = item.getType(); if (type.hasBlockType() && type.getBlockType().getMaterial().isAir()) { @@ -1603,4 +1609,13 @@ public class LocalSession implements TextureHolder { } } } + + private void prepareEditingExtents(EditSession editSession, Actor actor) { + editSession.setFastMode(fastMode); + editSession.setReorderMode(reorderMode); + if (editSession.getSurvivalExtent() != null) { + editSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); + } + editSession.setTickingWatchdog(tickingWatchdog); + } } 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/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index 10c16b5ab..b1e11cbd9 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 @@ -27,6 +27,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.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; @@ -81,6 +82,7 @@ public class BiomeCommands { 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(); @@ -97,7 +99,8 @@ public class BiomeCommands { } }) .collect(Collectors.toList())); - actor.print(paginationBox.create(page)); + return paginationBox.create(page); + }, null); } @Command( @@ -180,7 +183,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/command/BrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 48ef9f477..a681da433 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,8 +19,6 @@ package com.sk89q.worldedit.command; -import static com.google.common.base.Preconditions.checkNotNull; - import com.boydti.fawe.Fawe; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Settings; @@ -67,6 +65,7 @@ import com.sk89q.worldedit.EmptyClipboardException; 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.blocks.BaseItem; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; @@ -127,6 +126,7 @@ import java.nio.file.FileSystems; import java.util.List; import java.util.zip.GZIPInputStream; import org.enginehub.piston.annotation.Command; +import com.sk89q.worldedit.function.factory.Apply; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.ArgFlag; @@ -134,6 +134,8 @@ import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.Key; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Commands to set brush shape. */ @@ -152,6 +154,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 = "blendball", aliases = {"bb", "blend"}, @@ -644,18 +655,18 @@ public class BrushCommands { ) @Deprecated @CommandPermissions("worldedit.brush.clipboard") - public void clipboardBrush(LocalSession session, InjectedValueAccess context, - @Switch(name = 'a', desc = "Don't paste air from the clipboard") - boolean ignoreAir, - @Switch(name = 'o', desc = "Paste starting at the target location, instead of centering on it") - boolean usingOrigin, - @Switch(name = 'e', desc = "Skip paste entities if available") - boolean skipEntities, - @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 { + 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 starting at the target location, instead of centering on it") + boolean usingOrigin, + @Switch(name = 'e', desc = "Paste entities if available") + boolean pasteEntities, + @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(); @@ -678,13 +689,13 @@ public class BrushCommands { descFooter = "Example: '/brush smooth 2 4 grass_block,dirt,stone'" ) @CommandPermissions("worldedit.brush.smooth") - public void smoothBrush(Player player, InjectedValueAccess context, EditSession editSession, - @Arg(desc = "The radius to sample for softening", def = "2") - Expression 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 maskOpt) throws WorldEditException { + public void smoothBrush(Player player, LocalSession session, + @Arg(desc = "The radius to sample for softening", def = "2") + Expression 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 maskOpt) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); FaweLimit limit = Settings.IMP.getLimit(player); @@ -1089,4 +1100,106 @@ public class BrushCommands { player.print("Set brush to " + factory); } + + @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 shape, + @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, shape, "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 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)), shape, "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 shape, + @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), shape, "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 shape, + @Arg(desc = "The size of the brush", def = "5") + double radius) throws WorldEditException { + setOperationBasedBrush(player, localSession, radius, + new Deform("y-=1"), shape, "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 shape, + @Arg(desc = "The size of the brush", def = "5") + double radius) throws WorldEditException { + setOperationBasedBrush(player, localSession, radius, + new Deform("y+=1"), shape, "worldedit.brush.lower"); + } + + static void setOperationBasedBrush(Player player, LocalSession session, double radius, + Contextual factory, + 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, shape, session), permission); + + player.print("Set brush to " + factory); + } } 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 ce283ec47..b0474dece 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 @@ -18,8 +18,6 @@ */ package com.sk89q.worldedit.command; - -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; @@ -39,6 +37,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.command.util.WorldEditAsyncCommandBuilder; 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; @@ -46,9 +45,10 @@ 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 java.io.File; import java.io.IOException; import java.nio.file.Files; + +import java.io.File; import java.nio.file.Path; import java.time.ZonedDateTime; import java.util.ArrayList; @@ -59,6 +59,8 @@ import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.exception.StopExecutionException; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Commands for working with chunks. */ 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 9168b9bfe..054cc7055 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,6 +19,8 @@ package com.sk89q.worldedit.command; +import com.google.common.collect.Lists; + import com.boydti.fawe.FaweAPI; import com.boydti.fawe.FaweCache; import com.boydti.fawe.config.BBC; @@ -37,12 +39,10 @@ import com.boydti.fawe.util.MaskTraverser; 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.event.extent.PasteEvent; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.Extent; @@ -53,6 +53,8 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.function.block.BlockReplace; + +import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; @@ -91,11 +93,10 @@ import java.util.Set; import java.util.function.Supplier; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; - -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 java.util.List; + /** * Clipboard commands. @@ -103,18 +104,6 @@ import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; @CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class ClipboardCommands { - private WorldEdit worldEdit; - - /** - * Create a new instance. - * - * @param worldEdit reference to WorldEdit - */ - public ClipboardCommands(WorldEdit worldEdit) { - checkNotNull(worldEdit); - this.worldEdit = worldEdit; - } - @Command( name = "/copy", @@ -442,6 +431,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") @@ -457,6 +448,7 @@ public class ClipboardCommands { } Clipboard clipboard = holder.getClipboard(); Region region = clipboard.getRegion(); + List messages = Lists.newArrayList(); BlockVector3 to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(actor); checkPaste(actor, editSession, to, holder, clipboard); @@ -471,7 +463,7 @@ public class ClipboardCommands { .build(); Operations.completeLegacy(operation); - 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())); @@ -578,7 +570,7 @@ public class ClipboardCommands { AffineTransform transform = new AffineTransform(); transform = transform.scale(direction.abs().multiply(-2).add(1, 1, 1).toVector3()); holder.setTransform(holder.getTransform().combine(transform)); - actor.print(BBC.COMMAND_FLIPPED.s()); + actor.print("The clipboard copy has been flipped."); } @Command( @@ -588,6 +580,6 @@ public class ClipboardCommands { @CommandPermissions("worldedit.clipboard.clear") public void clearClipboard(Actor actor, LocalSession session) throws WorldEditException { session.setClipboard(null); - actor.print(BBC.CLIPBOARD_CLEARED.s()); + 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 393a95606..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 @@ -19,9 +19,6 @@ package com.sk89q.worldedit.command; -import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; -import static com.sk89q.worldedit.internal.command.CommandUtil.requireIV; - import com.google.common.collect.ImmutableSet; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; @@ -39,7 +36,6 @@ 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 java.util.List; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandManagerService; @@ -48,6 +44,11 @@ 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}. */ 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 f9fccfe8f..98c851b17 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,8 +19,6 @@ package com.sk89q.worldedit.command; -import static com.google.common.base.Preconditions.checkNotNull; - import com.boydti.fawe.Fawe; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.extent.ResettableExtent; @@ -44,6 +42,8 @@ import com.sk89q.worldedit.extension.input.DisallowedUsageException; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; + +import java.util.ArrayList; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.function.mask.Mask; @@ -52,7 +52,6 @@ import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.item.ItemType; import java.io.FileNotFoundException; -import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; @@ -64,6 +63,8 @@ import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.Switch; +import static com.google.common.base.Preconditions.checkNotNull; + /** * General WorldEdit commands. */ @@ -132,8 +133,8 @@ public class GeneralCommands { } @Command( - name = "/fast", - desc = "Toggle fast mode" + name = "/fast", + desc = "Toggle fast mode" ) @CommandPermissions("worldedit.fast") public void fast(Actor actor, LocalSession session, @@ -144,12 +145,13 @@ public class GeneralCommands { actor.printError("Fast mode already " + (fastMode ? "enabled" : "disabled") + "."); return; } + if (hasFastMode) { session.setFastMode(false); - actor.print(BBC.FAST_DISABLED.s()); + actor.print("Fast mode disabled."); } else { session.setFastMode(true); - actor.print(BBC.FAST_ENABLED.s()); + actor.print("Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes."); } } @@ -196,20 +198,20 @@ public class GeneralCommands { } } -// @Command( -// name = "/world", -// desc = "Sets the world override" -// ) -// @CommandPermissions("worldedit.world") -// public void worldOverride(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 = "/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 = "/watchdog", @@ -237,16 +239,18 @@ public class GeneralCommands { @Command( name = "gmask", aliases = {"/gmask"}, - descFooter = "The global destination mask applies to all edits you do and masks based on the destination blocks (i.e., the blocks in the world).", desc = "Set the global mask" ) - @CommandPermissions({"worldedit.global-mask", "worldedit.mask.global"}) - public void gmask(Actor actor, LocalSession session, @Arg(desc = "The mask to set", def = "") Mask mask) { - session.setMask(mask); + @CommandPermissions("worldedit.global-mask") + public void gmask(Actor actor, LocalSession session, + @Arg(desc = "The mask to set", def = "") + Mask mask) { if (mask == null) { - actor.print(BBC.MASK_DISABLED.s()); + session.setMask(null); + actor.print("Global mask disabled."); } else { - actor.print(BBC.MASK.s()); + session.setMask(mask); + actor.print("Global mask set."); } } @@ -291,7 +295,7 @@ public class GeneralCommands { actor.print(new ItemSearcher(search, blocksOnly, itemsOnly, page).call()); } - public static class ItemSearcher implements Callable { + private static class ItemSearcher implements Callable { private final boolean blocksOnly; private final boolean itemsOnly; private final String search; 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 695869f1b..6c32f8c1c 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 @@ -18,8 +18,6 @@ */ package com.sk89q.worldedit.command; - -import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.worldedit.command.MethodCommands.getArguments; import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; @@ -42,10 +40,13 @@ 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.generator.CavesGen; + +import java.util.List; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.visitor.RegionVisitor; +import com.sk89q.worldedit.internal.annotation.Radii; import com.sk89q.worldedit.internal.annotation.Range; import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.internal.expression.ExpressionException; @@ -61,11 +62,12 @@ import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URL; -import java.util.List; 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 org.enginehub.piston.inject.InjectedValueAccess; /** @@ -184,20 +186,15 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.cylinder") @Logging(PLACEMENT) - public void hcyl(Actor actor, 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. Order is N/S, E/W") BlockVector2 radius, + 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, - @Range(min = 1) @Arg(desc = "double", def = "1") double thickness, InjectedValueAccess context) throws WorldEditException { - double max = MathMan.max(radius.getBlockX(), radius.getBlockZ()); - worldEdit.checkMaxRadius(max); - BlockVector3 pos = session.getPlacementPosition(actor); - actor.checkConfirmationRadius(() -> { - int affected = editSession.makeHollowCylinder(pos, pattern, radius.getX(), radius.getZ(), Math.min(256, height), thickness - 1); - BBC.VISITOR_BLOCK.send(actor, affected); - }, "/hcyl", (int) max, context); + int height) throws WorldEditException { + return cyl(actor, session, editSession, pattern, radii, height, true); } @Command( @@ -278,9 +275,10 @@ public class GenerationCommands { int size, @Arg(desc = "The type of forest", def = "tree") TreeType type, - @Range(min = 0, max = 100) @Arg(desc = "The density of the forest, between 0 and 100", def = "5") + @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(actor), size, density, type); actor.print(affected + " trees created."); @@ -295,14 +293,10 @@ public class GenerationCommands { @Logging(POSITION) public int pumpkins(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The size of the patch", def = "10") - int size, - @Arg(desc = "//TODO", def = "10") - int apothem, - @Arg(desc = "//TODO ", def = "0.02") - double density) throws WorldEditException { - checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100"); - int affected = editSession.makePumpkinPatches(session.getPlacementPosition(actor), apothem, density); - BBC.COMMAND_PUMPKIN.send(actor, affected); + int size) throws WorldEditException { + worldEdit.checkMaxRadius(size); + int affected = editSession.makePumpkinPatches(session.getPlacementPosition(actor), size); + actor.print(affected + " pumpkin patches created."); return affected; } 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 7c17e23e6..0da8c3d74 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,8 +19,6 @@ package com.sk89q.worldedit.command; -import static com.google.common.base.Preconditions.checkNotNull; - import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweAPI; import com.boydti.fawe.config.BBC; @@ -57,6 +55,8 @@ import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.inject.InjectedValueAccess; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Commands to undo, redo, and clear history. */ @@ -223,6 +223,16 @@ public class HistoryCommands { aliases = { "/un", "/ud", "undo" }, desc = "Undoes the last action (from history)" ) + } else { + undoSession = session; + } + int finalTimes = times; + player.checkConfirmation(() -> { + EditSession undone = null; + int i = 0; + for (; i < finalTimes; ++i) { + undone = undoSession.undo(undoSession.getBlockBag(player), player); + if (undone == null) break; @CommandPermissions({"worldedit.history.undo", "worldedit.history.undo.self"}) public void undo(Player player, LocalSession session, @Range(min = 1) @Arg(desc = "Number of undoes to perform", def = "1") @@ -243,16 +253,6 @@ public class HistoryCommands { BBC.COMMAND_HISTORY_OTHER_ERROR.send(player, playerName); return; } - } else { - undoSession = session; - } - int finalTimes = times; - player.checkConfirmation(() -> { - EditSession undone = null; - int i = 0; - for (; i < finalTimes; ++i) { - undone = undoSession.undo(undoSession.getBlockBag(player), player); - if (undone == null) break; worldEdit.flushBlockBag(player, undone); } if (undone == null) i--; @@ -311,7 +311,7 @@ public class HistoryCommands { @CommandPermissions("worldedit.history.clear") public void clearHistory(Actor actor, LocalSession session) { session.clearHistory(); - actor.print(BBC.COMMAND_HISTORY_CLEAR.s()); + actor.print("History cleared."); } } 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 8a78a4f54..db483eb32 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 @@ -18,8 +18,6 @@ */ 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.boydti.fawe.config.BBC; @@ -36,6 +34,8 @@ 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 for moving the player around. */ @@ -62,7 +62,7 @@ public class NavigationCommands { @CommandPermissions("worldedit.navigation.unstuck") public void unstuck(Player player) throws WorldEditException { player.findFreePosition(); - player.print(BBC.UNSTUCK.s()); + player.print("There you go!"); } @Command( @@ -84,11 +84,7 @@ public class NavigationCommands { if (ascentLevels == 0) { player.printError(BBC.ASCEND_FAIL.s()); } else { - if (ascentLevels == 1) { - player.print(BBC.ASCENDED_SINGULAR.s()); - } else { - BBC.ASCENDED_PLURAL.send(player, ascentLevels); - } + player.print((ascentLevels != 1) ? "Ascended " + ascentLevels + " levels." : "Ascended a level."); } } @@ -113,7 +109,7 @@ public class NavigationCommands { } else if (descentLevels == 1) { player.print(BBC.DESCEND_SINGULAR.s()); } else { - BBC.DESCEND_PLURAL.send(player, descentLevels); + player.print((descentLevels != 1) ? "Descended " + descentLevels + " levels." : "Descended a level."); } } 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 2e9d9698b..203485780 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,19 +19,23 @@ package com.sk89q.worldedit.command; +import com.google.common.base.Joiner; + import com.boydti.fawe.FaweAPI; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.implementation.processors.ChunkSendProcessor; import com.boydti.fawe.beta.implementation.processors.NullProcessor; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FaweLimit; +import com.google.common.collect.Lists; import com.sk89q.jnbt.CompoundTag; 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.function.RegionFunction; +import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; @@ -39,9 +43,11 @@ import com.sk89q.worldedit.function.FlatRegionFunction; import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.biome.BiomeReplace; import com.sk89q.worldedit.function.generator.FloraGenerator; +import com.sk89q.worldedit.function.mask.MaskIntersection; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.NoiseFilter2D; +import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; @@ -63,6 +69,8 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.regions.Regions; + +import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.world.World; @@ -81,10 +89,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.stream.Stream; - -import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.worldedit.command.MethodCommands.getArguments; -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; @@ -98,16 +103,35 @@ import static com.sk89q.worldedit.regions.Regions.minimumBlockY; @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( + name = "/set", + desc = "Sets all the blocks in the region" + ) + @CommandPermissions("worldedit.region.set") + @Logging(REGION) + public int set(Actor actor, EditSession editSession, + @Selection Region region, + @Arg(desc = "The pattern 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()) { + actor.print("Operation completed."); + } else { + actor.print("Operation completed (" + Joiner.on(", ").join(messages) + ")."); + } + + return visitor.getAffected(); } @Command( @@ -254,7 +278,7 @@ public class RegionCommands { @Selection Region region, @Arg(desc = "The pattern of blocks to place") Pattern pattern, - @Range(min = 1) @Arg(desc = "The thickness of the line", def = "0") + @Arg(desc = "The thickness of the line", def = "0") int thickness, @Switch(name = 'h', desc = "Generate only a shell") boolean shell) throws WorldEditException { @@ -269,7 +293,7 @@ public class RegionCommands { BlockVector3 pos2 = cuboidregion.getPos2(); int blocksChanged = editSession.drawLine(pattern, pos1, pos2, thickness, !shell); - BBC.VISITOR_BLOCK.send(actor, blocksChanged); + actor.print(blocksChanged + " block(s) have been changed."); return blocksChanged; } @@ -290,7 +314,7 @@ public class RegionCommands { boolean shell, InjectedValueAccess context) throws WorldEditException { if (!(region instanceof ConvexPolyhedralRegion)) { actor.printError("//curve only works with convex polyhedral selections"); - return; + return 0; } checkCommandArgument(thickness >= 0, "Thickness must be >= 0"); @@ -300,7 +324,7 @@ public class RegionCommands { int blocksChanged = editSession.drawSpline(pattern, vectors, 0, 0, 0, 10, thickness, !shell); - BBC.VISITOR_BLOCK.send(actor, blocksChanged); + actor.print(blocksChanged + " block(s) have been changed."); }, getArguments(context), region, context); } @@ -321,14 +345,8 @@ public class RegionCommands { } Mask finalFrom = from; actor.checkConfirmationRegion(() -> { - int affected = editSession.replaceBlocks(region, finalFrom, to); - BBC.VISITOR_BLOCK.send(actor, affected); - if (!actor.hasPermission("fawe.tips")) { - BBC.TIP_REPLACE_ID - .or(BBC.TIP_REPLACE_LIGHT, BBC.TIP_REPLACE_MARKER, BBC.TIP_TAB_COMPLETE, - BBC.TIP_REPLACE_REGEX, BBC.TIP_REPLACE_REGEX_2, BBC.TIP_REPLACE_REGEX_3, - BBC.TIP_REPLACE_REGEX_4, BBC.TIP_REPLACE_REGEX_5).send(actor); - } + int affected = editSession.replaceBlocks(region, finalFrom, to); + actor.print(affected + " block(s) have been replaced."); }, getArguments(context), region, context); } @@ -342,8 +360,8 @@ public class RegionCommands { @Arg(desc = "The pattern of blocks to overlay") Pattern pattern, InjectedValueAccess context) throws WorldEditException { actor.checkConfirmationRegion(() -> { - int affected = editSession.overlayCuboidBlocks(region, pattern); - BBC.VISITOR_BLOCK.send(actor, affected); + int affected = editSession.overlayCuboidBlocks(region, pattern); + actor.print(affected + " block(s) have been overlaid."); }, getArguments(context), region, context); } @@ -380,11 +398,12 @@ public class RegionCommands { ) @Logging(REGION) @CommandPermissions("worldedit.region.center") - public void center(Actor actor, 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); - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print("Center set (" + affected + " block(s) changed)"); + return affected; } @Command( @@ -396,7 +415,7 @@ public class RegionCommands { public void naturalize(Actor actor, EditSession editSession, @Selection Region region, InjectedValueAccess context) throws WorldEditException { actor.checkConfirmationRegion(() -> { int affected = editSession.naturalizeCuboidBlocks(region); - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print(affected + " block(s) have been made to look more natural."); }, getArguments(context), region, context); } @@ -411,7 +430,7 @@ public class RegionCommands { Pattern pattern, InjectedValueAccess context) throws WorldEditException { actor.checkConfirmationRegion(() -> { int affected = editSession.makeWalls(region, pattern); - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print(affected + " block(s) have been changed."); }, getArguments(context), region, context); } @@ -427,7 +446,7 @@ public class RegionCommands { Pattern pattern, InjectedValueAccess context) throws WorldEditException { actor.checkConfirmationRegion(() -> { int affected = editSession.makeCuboidFaces(region, pattern); - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print(affected + " block(s) have been changed."); }, getArguments(context), region, context); } @@ -456,7 +475,7 @@ public class RegionCommands { HeightMap heightMap = new HeightMap(editSession, region, mask, snow); HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); int affected = heightMap.applyFilter(filter, iterations); - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print("Terrain's height map smoothed. " + affected + " block(s) changed."); } catch (Throwable e) { throw new RuntimeException(e); } @@ -522,8 +541,20 @@ public class RegionCommands { boolean copyBiomes, InjectedValueAccess context) throws WorldEditException { checkCommandArgument(count >= 1, "Count must be >= 1"); + + Mask combinedMask; + if (ignoreAirBlocks) { + if (mask == null) { + combinedMask = new ExistingBlockMask(editSession); + } else { + combinedMask = new MaskIntersection(mask, new ExistingBlockMask(editSession)); + } + } else { + combinedMask = mask; + } + actor.checkConfirmationRegion(() -> { - int affected = editSession.moveRegion(region, direction, count, !ignoreAirBlocks, !skipEntities, copyBiomes, replace); + int affected = editSession.moveRegion(region, direction, count, !ignoreAirBlocks, !skipEntities, copyBiomes, combinedMask, replace); if (moveSelection) { try { @@ -583,17 +614,29 @@ public class RegionCommands { @ArgFlag(name = 'm', desc = "Source mask", def="") Mask sourceMask, InjectedValueAccess context) throws WorldEditException { + + Mask combinedMask; + if (ignoreAirBlocks) { + if (mask == null) { + combinedMask = new ExistingBlockMask(editSession); + } else { + combinedMask = new MaskIntersection(mask, new ExistingBlockMask(editSession)); + } + } else { + combinedMask = mask; + } + actor.checkConfirmationStack(() -> { if (sourceMask != null) { editSession.addSourceMask(sourceMask); } - int affected = editSession.stackCuboidRegion(region, direction, count, !ignoreAirBlocks, !skipEntities, copyBiomes); + int affected = editSession.stackCuboidRegion(region, direction, count, !skipEntities, copyBiomes, combinedMask); 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(); @@ -652,7 +695,7 @@ public class RegionCommands { if (actor instanceof Player) { ((Player) actor).findFreePosition(); } - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print(affected + " block(s) have been deformed."); } catch (ExpressionException e) { actor.printError(e.getMessage()); } @@ -718,7 +761,7 @@ public class RegionCommands { Mask finalMask = mask == null ? new SolidBlockMask(editSession) : mask; actor.checkConfirmationRegion(() -> { int affected = editSession.hollowOutRegion(region, thickness, pattern, finalMask); - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print(affected + " block(s) have been changed."); }, getArguments(context), region, context); } @@ -735,7 +778,7 @@ public class RegionCommands { double density) throws WorldEditException { checkCommandArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); int affected = editSession.makeForest(region, density / 100, type); - BBC.COMMAND_TREE.send(actor, affected); + actor.print(affected + " trees created."); return affected; } @@ -756,7 +799,7 @@ public class RegionCommands { visitor.setMask(new NoiseFilter2D(new RandomNoise(), density / 100)); Operations.completeLegacy(visitor); - BBC.COMMAND_FLORA.send(actor, ground.getAffected()); + actor.print(affected + " flora created."); }, "/flora", region, context); } 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 c962d3d36..0c148fcb8 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 @@ -20,7 +20,6 @@ package com.sk89q.worldedit.command; import static com.boydti.fawe.util.ReflectionUtils.as; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import com.boydti.fawe.config.BBC; @@ -41,6 +40,7 @@ import com.sk89q.worldedit.command.argument.Arguments; 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.event.extent.ActorSaveClipboardEvent; import com.sk89q.worldedit.extension.platform.Actor; @@ -60,6 +60,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.event.HoverEvent; +import com.sk89q.worldedit.util.formatting.component.CodeFormat; import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.io.Closer; import com.sk89q.worldedit.util.io.file.FilenameException; @@ -70,6 +71,8 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; + +import static com.google.common.base.Preconditions.checkArgument; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; @@ -843,6 +846,24 @@ public class SchematicCommands { return fileList; } + @Command( + name = "delete", + aliases = {"d"}, + desc = "Delete a saved schematic" + ) + @CommandPermissions("worldedit.schematic.delete") + public void delete(Actor actor, + @Arg(desc = "File name.") + String filename) throws WorldEditException { + LocalConfiguration config = worldEdit.getConfiguration(); + File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); + + File f = worldEdit.getSafeOpenFile(actor instanceof Player ? ((Player) actor) : null, + dir, filename, "schematic", ClipboardFormats.getFileExtensionArray()); + + if (!f.exists()) { + actor.printError("Schematic " + filename + " does not exist!"); + return; private boolean delete(File file) { if (file.delete()) { new File(file.getParentFile(), "." + file.getName() + ".cached").delete(); 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 19dc072e4..dbbaf47c2 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 @@ -18,8 +18,6 @@ */ 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.boydti.fawe.config.BBC; @@ -39,6 +37,8 @@ import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.inject.InjectedValueAccess; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Commands related to scripting. @@ -68,8 +68,8 @@ public class ScriptingCommands { } @Command( - name = "cs", - desc = "Execute a CraftScript" + name = "cs", + desc = "Execute a CraftScript" ) @CommandPermissions("worldedit.scripting.execute") @Logging(ALL) @@ -77,9 +77,9 @@ public class ScriptingCommands { @Arg(desc = "Filename of the CraftScript to load") String filename, @Arg(desc = "Arguments to the CraftScript", def = "", variable = true) - List commandStr) throws WorldEditException { + List args) throws WorldEditException { if (!player.hasPermission("worldedit.scripting.execute." + filename)) { - player.printError(BBC.SCRIPTING_NO_PERM.s()); + player.printError("You don't have permission to use that script."); return; } @@ -88,19 +88,19 @@ public class ScriptingCommands { File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir); File f = worldEdit.getSafeOpenFile(player, dir, filename, "js", "js"); - worldEdit.runScript(player, f, Stream.concat(Stream.of(filename), commandStr.stream()) - .toArray(String[]::new)); + worldEdit.runScript(player, f, Stream.concat(Stream.of(filename), args.stream()) + .toArray(String[]::new)); } @Command( - name = ".s", - desc = "Execute last CraftScript" + name = ".s", + desc = "Execute last CraftScript" ) @CommandPermissions("worldedit.scripting.execute") @Logging(ALL) public void executeLast(Player player, LocalSession session, @Arg(desc = "Arguments to the CraftScript", def = "", variable = true) - List commandStr) throws WorldEditException { + List args) throws WorldEditException { String lastScript = session.getLastScript(); @@ -117,7 +117,7 @@ public class ScriptingCommands { File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir); File f = worldEdit.getSafeOpenFile(player, dir, lastScript, "js", "js"); - worldEdit.runScript(player, f, Stream.concat(Stream.of(lastScript), commandStr.stream()) - .toArray(String[]::new)); + 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/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 6762cb596..6a3349890 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,8 @@ package com.sk89q.worldedit.command; +import com.google.common.base.Strings; + import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; @@ -44,6 +46,7 @@ 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.AbstractDelegateExtent; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.annotation.Direction; @@ -77,12 +80,19 @@ import com.sk89q.worldedit.world.storage.ChunkStore; import java.io.File; import java.net.URI; import java.util.List; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import com.sk89q.worldedit.util.formatting.component.InvalidComponentException; +import com.sk89q.worldedit.util.formatting.text.Component; import java.util.Optional; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import java.util.stream.Stream; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; +import com.sk89q.worldedit.world.block.BlockType; import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Switch; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.exception.StopExecutionException; /** * Selection commands. @@ -98,7 +108,6 @@ public class SelectionCommands { @Command( name = "/pos1", - aliases = "/1", desc = "Set position 1" ) @Logging(POSITION) @@ -116,18 +125,17 @@ public class SelectionCommands { return; } - if (!session.getRegionSelector(world).selectPrimary(pos.toBlockPoint(), ActorSelectorLimits.forActor(actor))) { - actor.printError(BBC.SELECTOR_ALREADY_SET.s()); + if (!session.getRegionSelector(world).selectPrimary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(actor))) { + actor.printError("Position already set."); return; } session.getRegionSelector(world) - .explainPrimarySelection(actor, session, pos.toBlockPoint()); + .explainPrimarySelection(actor, session, pos.toVector().toBlockPoint()); } @Command( name = "/pos2", - aliases = "/2", desc = "Set position 2" ) @Logging(POSITION) @@ -145,13 +153,13 @@ public class SelectionCommands { return; } - if (!session.getRegionSelector(world).selectSecondary(pos.toBlockPoint(), ActorSelectorLimits.forActor(actor))) { - actor.printError(BBC.SELECTOR_ALREADY_SET.s()); + if (!session.getRegionSelector(world).selectSecondary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(actor))) { + actor.printError("Position already set."); return; } session.getRegionSelector(world) - .explainSecondarySelection(actor, session, pos.toBlockPoint()); + .explainSecondarySelection(actor, session, pos.toVector().toBlockPoint()); } @Command( @@ -204,7 +212,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") @@ -213,7 +221,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); @@ -223,7 +230,9 @@ 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); - BBC.SELECTION_CHUNKS.send(player, min2D.getBlockX() + ", " + min2D.getBlockZ(), max2D.getBlockX() + ", " + max2D.getBlockZ()); + actor.print("Chunks selected: (" + + min2D.getBlockX() + ", " + min2D.getBlockZ() + ") - (" + + max2D.getBlockX() + ", " + max2D.getBlockZ() + ")"); } else { final BlockVector2 min2D; if (coordinates != null) { @@ -233,13 +242,18 @@ public class SelectionCommands { : ChunkStore.toChunk(coordinates.toBlockVector3()); } else { // use player loc - min2D = ChunkStore.toChunk(player.getBlockLocation().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); - BBC.SELECTION_CHUNK.send(player, min2D.getBlockX() + ", " + min2D.getBlockZ()); + actor.print("Chunk selected: " + + min2D.getBlockX() + ", " + min2D.getBlockZ()); } final CuboidRegionSelector selector; @@ -248,11 +262,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); } @@ -333,8 +347,7 @@ public class SelectionCommands { session.getRegionSelector(world).explainRegionAdjust(actor, session); - - BBC.SELECTION_CONTRACT.send(actor, (oldSize - newSize)); + actor.print("Region contracted " + (oldSize - newSize) + " blocks."); } catch (RegionOperationException e) { actor.printError(e.getMessage()); } @@ -363,7 +376,7 @@ public class SelectionCommands { session.getRegionSelector(world).explainRegionAdjust(actor, session); - actor.print(BBC.SELECTION_SHIFT.s()); + actor.print("Region shifted."); } catch (RegionOperationException e) { actor.printError(e.getMessage()); } @@ -386,7 +399,7 @@ public class SelectionCommands { region.expand(getChangesForEachDir(amount, onlyHorizontal, onlyVertical)); session.getRegionSelector(world).learnChanges(); session.getRegionSelector(world).explainRegionAdjust(actor, session); - actor.print(BBC.SELECTION_OUTSET.s()); + actor.print("Region outset."); } @Command( @@ -496,11 +509,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); - BBC.SELECTION_COUNT.send(player, count); + int count = editSession.countBlocks(session.getSelection(world), mask); + actor.print("Counted: " + count); } @Command( @@ -531,7 +544,7 @@ public class SelectionCommands { if (distribution.isEmpty()) { // *Should* always be false - player.printError("No blocks counted."); + actor.printError("No blocks counted."); return; } @@ -549,6 +562,65 @@ public class SelectionCommands { } } + 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); + } + } + @Command( name = "/sel", aliases = { ";", "/desel", "/deselect" }, 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 d510f81f6..aceded7d2 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 @@ -76,7 +76,7 @@ public class SnapshotCommands { LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { - actor.printError(BBC.SNAPSHOT_NOT_CONFIGURED.s()); + actor.printError("Snapshot/backup restore is not configured."); return; } @@ -86,7 +86,7 @@ public class SnapshotCommands { if (!snapshots.isEmpty()) { actor.print(new SnapshotListBox(world.getName(), snapshots).create(page)); } else { - actor.printError(BBC.SNAPSHOT_NOT_AVAILABLE.s()); + actor.printError("No snapshots are available. See console for details."); // Okay, let's toss some debugging information! File dir = config.snapshotRepo.getDirectory(); @@ -101,7 +101,7 @@ public class SnapshotCommands { } } } catch (MissingWorldException ex) { - actor.printError(BBC.SNAPSHOT_NOT_FOUND_WORLD.s()); + actor.printError("No snapshots were found for this world."); } } @@ -117,7 +117,7 @@ public class SnapshotCommands { LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { - actor.printError(BBC.SNAPSHOT_NOT_CONFIGURED.s()); + actor.printError("Snapshot/backup restore is not configured."); return; } @@ -128,19 +128,19 @@ public class SnapshotCommands { if (snapshot != null) { session.setSnapshot(null); - actor.print(BBC.SNAPSHOT_NEWEST.s()); + actor.print("Now using newest snapshot."); } else { - actor.printError(BBC.SNAPSHOT_NOT_FOUND.s()); + actor.printError("No snapshots were found."); } } catch (MissingWorldException ex) { - actor.printError(BBC.SNAPSHOT_NOT_FOUND_WORLD.s()); + actor.printError("No snapshots were found for this world."); } } else { try { session.setSnapshot(config.snapshotRepo.getSnapshot(name)); - BBC.SNAPSHOT_SET.send(actor, name); + actor.print("Snapshot set to: " + name); } catch (InvalidSnapshotException e) { - actor.printError(BBC.SNAPSHOT_NOT_AVAILABLE.s()); + actor.printError("That snapshot does not exist or is not available."); } } } @@ -156,12 +156,12 @@ public class SnapshotCommands { LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { - actor.printError(BBC.SNAPSHOT_NOT_CONFIGURED.s()); + actor.printError("Snapshot/backup restore is not configured."); return; } if (index < 1) { - actor.printError(BBC.SNAPSHOT_INVALID_INDEX.s()); + actor.printError("Invalid index, must be equal or higher then 1."); return; } @@ -173,13 +173,13 @@ public class SnapshotCommands { } Snapshot snapshot = snapshots.get(index - 1); if (snapshot == null) { - actor.printError(BBC.SNAPSHOT_NOT_AVAILABLE.s()); + actor.printError("That snapshot does not exist or is not available."); return; } session.setSnapshot(snapshot); - BBC.SNAPSHOT_SET.send(actor, snapshot.getName()); + actor.print("Snapshot set to: " + snapshot.getName()); } catch (MissingWorldException e) { - actor.printError(BBC.SNAPSHOT_NOT_FOUND_WORLD.s()); + actor.printError("No snapshots were found for this world."); } } @@ -195,7 +195,7 @@ public class SnapshotCommands { LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { - actor.printError(BBC.SNAPSHOT_NOT_CONFIGURED.s()); + actor.printError("Snapshot/backup restore is not configured."); return; } @@ -207,10 +207,10 @@ public class SnapshotCommands { + dateFormat.withZone(session.getTimeZone()).format(date) + "."); } else { session.setSnapshot(snapshot); - BBC.SNAPSHOT_SET.send(actor, snapshot.getName()); + actor.print("Snapshot set to: " + snapshot.getName()); } } catch (MissingWorldException ex) { - actor.printError(BBC.SNAPSHOT_NOT_FOUND_WORLD.s()); + actor.printError("No snapshots were found for this world."); } } @@ -226,7 +226,7 @@ public class SnapshotCommands { LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { - actor.printError(BBC.SNAPSHOT_NOT_CONFIGURED.s()); + actor.printError("Snapshot/backup restore is not configured."); return; } @@ -240,7 +240,7 @@ public class SnapshotCommands { actor.print("Snapshot set to: " + snapshot.getName()); } } catch (MissingWorldException ex) { - actor.printError(BBC.SNAPSHOT_NOT_FOUND_WORLD.s()); + 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 920127475..45a516218 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 @@ -68,7 +68,7 @@ public class SnapshotUtilCommands { LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { - actor.printError(BBC.SNAPSHOT_NOT_CONFIGURED.s()); + actor.printError("Snapshot/backup restore is not configured."); return; } @@ -79,7 +79,7 @@ public class SnapshotUtilCommands { try { snapshot = config.snapshotRepo.getSnapshot(snapshotName); } catch (InvalidSnapshotException e) { - actor.printError(BBC.SNAPSHOT_NOT_AVAILABLE.s()); + actor.printError("That snapshot does not exist or is not available."); return; } } else { @@ -92,7 +92,7 @@ public class SnapshotUtilCommands { snapshot = config.snapshotRepo.getDefaultSnapshot(world.getName()); if (snapshot == null) { - actor.printError(BBC.SNAPSHOT_NOT_AVAILABLE.s()); + actor.printError("No snapshots were found. See console for details."); // Okay, let's toss some debugging information! File dir = config.snapshotRepo.getDirectory(); @@ -109,15 +109,21 @@ public class SnapshotUtilCommands { return; } } catch (MissingWorldException ex) { - actor.printError(BBC.SNAPSHOT_NOT_FOUND_WORLD.s()); + actor.printError("No snapshots were found for this world."); return; } } + ChunkStore chunkStore; // Load chunk store - try (ChunkStore chunkStore = snapshot.getChunkStore()) { - BBC.SNAPSHOT_LOADED.send(actor, snapshot.getName()); + try { + chunkStore = snapshot.getChunkStore(); + actor.print("Snapshot '" + snapshot.getName() + "' loaded; now restoring..."); + } catch (DataException | IOException e) { + actor.printError("Failed to load snapshot: " + e.getMessage()); + return; + } // Restore snapshot SnapshotRestore restore = new SnapshotRestore(chunkStore, editSession, region); @@ -128,12 +134,12 @@ public class SnapshotUtilCommands { if (restore.hadTotalFailure()) { String error = restore.getLastErrorMessage(); if (!restore.getMissingChunks().isEmpty()) { - actor.printError(BBC.SNAPSHOT_ERROR_RESTORE.s()); + actor.printError("Chunks were not present in snapshot."); } else if (error != null) { actor.printError("Errors prevented any blocks from being restored."); actor.printError("Last error: " + error); } else { - actor.printError(BBC.SNAPSHOT_ERROR_RESTORE_CHUNKS.s()); + actor.printError("No chunks could be loaded. (Bad archive?)"); } } else { actor.print(String.format("Restored; %d " @@ -143,6 +149,6 @@ public class SnapshotUtilCommands { } } catch (DataException | IOException e) { actor.printError("Failed to load snapshot: " + e.getMessage()); + } } - } } 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 52f7f0c9e..b6e452d24 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,8 @@ package com.sk89q.worldedit.command; +import com.google.common.collect.Collections2; + import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.brush.InspectBrush; import com.sk89q.worldedit.LocalConfiguration; @@ -28,6 +30,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.command.tool.BlockDataCyler; import com.sk89q.worldedit.command.tool.BlockReplacer; +import com.sk89q.worldedit.command.tool.InvalidToolBindException; import com.sk89q.worldedit.command.tool.DistanceWand; import com.sk89q.worldedit.command.tool.FloatingTreeRemover; import com.sk89q.worldedit.command.tool.FloodFillTool; @@ -44,27 +47,95 @@ 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 com.sk89q.worldedit.internal.command.CommandRegistrationHandler; +import com.sk89q.worldedit.internal.command.CommandUtil; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandManagerService; +import org.enginehub.piston.CommandMetadata; +import org.enginehub.piston.CommandParameters; +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) { + 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, "Global tool names cause conflicts " + + "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; + } + + 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) { this.we = we; } -// @Command( -// name = "none", -// 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."); -// } - @Command( name = "selwand", aliases = "/selwand", @@ -74,7 +145,7 @@ public class ToolCommands { public void selwand(Player player, LocalSession session) throws WorldEditException { final ItemType itemType = player.getItemInHand(HandSide.MAIN_HAND).getType(); - session.setTool(player, SelectionWand.INSTANCE); + session.setTool(itemType, new SelectionWand()); player.print("Selection wand bound to " + itemType.getName() + "."); } @@ -215,8 +286,17 @@ public class ToolCommands { Pattern secondary) throws WorldEditException { BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); - session.setTool(player, new LongRangeBuildTool(primary, secondary)); - BBC.TOOL_LRBUILD_BOUND.send(player, itemStack.getType().getName()); - BBC.TOOL_LRBUILD_INFO.send(player, secondary, primary); + session.setTool(itemStack.getType(), new LongRangeBuildTool(primary, secondary)); + player.print("Long-range building tool bound to " + itemStack.getType().getName() + "."); + String primaryName = "pattern"; + String secondaryName = "pattern"; + if (primary instanceof BlockStateHolder) { + primaryName = ((BlockStateHolder) primary).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/ToolUtilCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java index 66b49f89e..7f8881815 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 @@ -82,16 +82,16 @@ public class ToolUtilCommands { return; } if (maskOpt == null) { - player.print(BBC.BRUSH_MASK_DISABLED.s()); + player.print("Brush mask disabled."); tool.setMask(null); return; - } + } BrushSettings settings = offHand ? tool.getOffHand() : tool.getContext(); String lastArg = Iterables.getLast(CommandArgParser.spaceSplit(arguments.get())).getSubstring(); settings.addSetting(BrushSettings.SettingType.MASK, lastArg); settings.setMask(maskOpt); tool.update(); - player.print(BBC.BRUSH_MASK.s()); + player.print("Brush mask set."); } @Command( @@ -110,7 +110,7 @@ public class ToolUtilCommands { if (tool == null) { player.print(BBC.BRUSH_NONE.s()); return; - } + } if (pattern == null) { player.print(BBC.BRUSH_MATERIAL.s()); tool.setFill(null); @@ -125,61 +125,29 @@ public class ToolUtilCommands { } @Command( - name = "range", - desc = "Set the brush range" - ) + name = "range", + desc = "Set the brush range" + ) @CommandPermissions("worldedit.brush.options.range") public void range(Player player, LocalSession session, @Arg(desc = "The range of the brush") - int range) throws WorldEditException { - range = Math.max(0, Math.min(256, range)); - BrushTool tool = session.getBrushTool(player, false); - if (tool == null) { - player.print(BBC.BRUSH_NONE.s()); - return; - } - tool.setRange(range); - player.print(BBC.BRUSH_RANGE.s()); + int range) throws WorldEditException { + session.getBrushTool(player, false).setRange(range); + player.print("Brush range set."); } @Command( - name = "size", - desc = "Set the brush size" + name = "size", + desc = "Set the brush size" ) @CommandPermissions("worldedit.brush.options.size") public void size(Player player, LocalSession session, - @Arg(desc = "The size of the brush", def = "5") - int size, - @Switch(name = 'h', desc = "TODO") - boolean offHand) throws WorldEditException { + @Arg(desc = "The size of the brush") + int size) throws WorldEditException { we.checkMaxBrushRadius(size); - BrushTool tool = session.getBrushTool(player, false); - if (tool == null) { - player.print(BBC.BRUSH_NONE.s()); - return; - } - BrushSettings settings = offHand ? tool.getOffHand() : tool.getContext(); - settings.setSize(size); - tool.update(); - player.print(BBC.BRUSH_SIZE.s()); - } - @Command( - name = "tracemask", - aliases = {"tarmask", "tm", "targetmask"}, - 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 maskOpt) throws WorldEditException { - BrushTool tool = session.getBrushTool(player, false); - if (tool == null) { - player.print(BBC.BRUSH_NONE.s()); - return; - } - tool.setTraceMask(maskOpt); - BBC.BRUSH_TARGET_MASK_SET.send(player, maskOpt.toString()); + session.getBrushTool(player, false).setSize(size); + player.print("Brush size set."); } //todo none should be moved to the same class where it is in upstream @@ -194,28 +162,42 @@ public class ToolUtilCommands { } @Command( - name = "/superpickaxe", - aliases = {",", "/sp", "/pickaxe"}, - desc = "Toggle the super pickaxe function" + name = "tracemask", + aliases = {"tarmask", "tm", "targetmask"}, + 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 maskOpt) throws WorldEditException { + session.getBrushTool(player, false).setTraceMask(maskOpt); + if (maskOpt == null) { + player.print("Trace mask disabled."); + } else { + player.print("Trace mask set."); + } + } + + @Command( + name = "/", + aliases = { "," }, + desc = "Toggle the super pickaxe function" ) @CommandPermissions("worldedit.superpickaxe") public void togglePickaxe(Player player, LocalSession session, - @Arg(desc = "state", def = "on") String state) throws WorldEditException { - if (session.hasSuperPickAxe()) { - if ("on".equals(state)) { - player.print(BBC.SUPERPICKAXE_ENABLED.s()); + @Arg(desc = "The new super pickaxe state", def = "") + Boolean superPickaxe) { + boolean hasSuperPickAxe = session.hasSuperPickAxe(); + if (superPickaxe != null && superPickaxe == hasSuperPickAxe) { + player.printError("Super pickaxe already " + (superPickaxe ? "enabled" : "disabled") + "."); return; } - + if (hasSuperPickAxe) { session.disableSuperPickAxe(); - player.print(BBC.SUPERPICKAXE_DISABLED.s()); + player.print("Super pickaxe disabled."); } else { - if ("off".equals(state)) { - player.print(BBC.SUPERPICKAXE_DISABLED.s()); - return; - } session.enableSuperPickAxe(); - player.print(BBC.SUPERPICKAXE_ENABLED.s()); + player.print("Super pickaxe enabled."); } } 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 5314787ab..0008b8b78 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 @@ -30,7 +30,6 @@ import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.image.ImageUtil; import com.google.common.base.Function; import com.google.common.collect.Lists; -import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalConfiguration; @@ -46,21 +45,23 @@ import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.PrintCommandHelp; import com.sk89q.worldedit.command.util.SkipQueue; import com.sk89q.worldedit.entity.Entity; -import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.function.EntityFunction; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.visitor.EntityVisitor; import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.Range; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; -import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; + +import java.text.DecimalFormat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CylinderRegion; @@ -77,7 +78,6 @@ import java.io.File; import java.io.IOException; import java.net.URI; import java.nio.file.Files; -import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.AbstractMap; import java.util.ArrayList; @@ -99,7 +99,8 @@ import org.enginehub.piston.annotation.param.Switch; /** * Utility commands. */ -@CommandContainer(superTypes = { +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) +public class UtilityCommands { // CommandQueuedConditionGenerator.Registration.class, CommandPermissionsConditionGenerator.Registration.class // TODO NOT IMPLEMENTED - Piston doesn't seem to work with multiple conditions??? }) @@ -193,6 +194,7 @@ public class UtilityCommands { @Command( name = "/fill", desc = "Fill a hole" + ) @CommandPermissions("worldedit.fill") @Logging(PLACEMENT) @@ -218,6 +220,8 @@ public class UtilityCommands { /* @Command( + name = "/fillr", + desc = "Fill a hole recursively" name = "patterns", desc = "View help about patterns", descFooter = "Patterns determine what blocks are placed\n" + @@ -296,10 +300,10 @@ public class UtilityCommands { public int fillr(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The blocks to fill with") Pattern pattern, - @Range(min=1) @Arg(desc = "The radius to fill in") + @Arg(desc = "The radius to fill in") Expression radiusExp, @Arg(desc = "The depth to fill", def = "") - Integer depth) throws WorldEditException, EvaluationException { + Integer depth) throws WorldEditException { double radius = radiusExp.evaluate(); radius = Math.max(1, radius); we.checkMaxRadius(radius); @@ -319,10 +323,10 @@ public class UtilityCommands { @CommandPermissions("worldedit.drain") @Logging(PLACEMENT) public int drain(Actor actor, LocalSession session, EditSession editSession, - @Range(min=0) @Arg(desc = "The radius to drain") + @Arg(desc = "The radius to drain") Expression radiusExp, @Switch(name = 'w', desc = "Also un-waterlog blocks") - boolean waterlogged) throws WorldEditException, EvaluationException { + boolean waterlogged) throws WorldEditException { double radius = radiusExp.evaluate(); radius = Math.max(0, radius); we.checkMaxRadius(radius); @@ -340,9 +344,8 @@ public class UtilityCommands { @CommandPermissions("worldedit.fixlava") @Logging(PLACEMENT) public int fixLava(Actor actor, LocalSession session, EditSession editSession, - @Range(min=0) @Arg(desc = "The radius to fix in") - Expression radiusExp) throws WorldEditException, EvaluationException { - double radius = radiusExp.evaluate(); + @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(actor), radius, BlockTypes.LAVA); @@ -358,13 +361,12 @@ public class UtilityCommands { @CommandPermissions("worldedit.fixwater") @Logging(PLACEMENT) public int fixWater(Actor actor, LocalSession session, EditSession editSession, - @Range(min=0) @Arg(desc = "The radius to fix in") - Expression radiusExp) throws WorldEditException, EvaluationException { - double radius = radiusExp.evaluate(); + @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(actor), radius, BlockTypes.WATER); - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print(affected + " block(s) have been changed."); return affected; } @@ -376,15 +378,16 @@ public class UtilityCommands { @CommandPermissions("worldedit.removeabove") @Logging(PLACEMENT) public int removeAbove(Actor actor, World world, LocalSession session, EditSession editSession, - @Range(min=1) @Arg(name = "size", desc = "The apothem of the square to remove from", def = "1") + @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); height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1); + int affected = editSession.removeAbove(session.getPlacementPosition(actor), size, height); - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print(affected + " block(s) have been removed."); return affected; } @@ -396,7 +399,7 @@ public class UtilityCommands { @CommandPermissions("worldedit.removebelow") @Logging(PLACEMENT) public int removeBelow(Actor actor, World world, LocalSession session, EditSession editSession, - @Arg(name = "size", desc = "The apothem of the square to remove from", def = "1") + @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 { @@ -405,7 +408,7 @@ public class UtilityCommands { height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1); int affected = editSession.removeBelow(session.getPlacementPosition(actor), size, height); - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print(affected + " block(s) have been removed."); return affected; } @@ -419,25 +422,25 @@ public class UtilityCommands { public int removeNear(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The mask of blocks to remove") Mask mask, - @Range(min=1) @Arg(desc = "The radius of the square to remove from", def = "50") + @Arg(desc = "The radius of the square to remove from", def = "50") int radius) throws WorldEditException { radius = Math.max(1, radius); we.checkMaxRadius(radius); int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, radius); - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print(affected + " block(s) have been removed."); return affected; } @Command( name = "replacenear", - aliases = { "/replacenear", "/rn" }, + aliases = { "/replacenear" }, desc = "Replace nearby blocks" ) @CommandPermissions("worldedit.replacenear") @Logging(PLACEMENT) public int replaceNear(Actor actor, World world, LocalSession session, EditSession editSession, - @Range(min=1) @Arg(desc = "The radius of the square to remove in") + @Arg(desc = "The radius of the square to remove in") int radius, @Arg(desc = "The mask matching blocks to remove", def = "") Mask from, @@ -456,7 +459,7 @@ public class UtilityCommands { } int affected = editSession.replaceBlocks(region, from, to); - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print(affected + " block(s) have been replaced."); return affected; } @@ -468,7 +471,7 @@ public class UtilityCommands { @CommandPermissions("worldedit.snow") @Logging(PLACEMENT) public int snow(Actor actor, LocalSession session, EditSession editSession, - @Range(min=1) @Arg(desc = "The radius of the circle to snow in", def = "10") + @Arg(desc = "The radius of the circle to snow in", def = "10") double size) throws WorldEditException { size = Math.max(1, size); we.checkMaxRadius(size); @@ -486,7 +489,7 @@ public class UtilityCommands { @CommandPermissions("worldedit.thaw") @Logging(PLACEMENT) public int thaw(Actor actor, LocalSession session, EditSession editSession, - @Range(min=1) @Arg(desc = "The radius of the circle to thaw in", def = "10") + @Arg(desc = "The radius of the circle to thaw in", def = "10") double size) throws WorldEditException { size = Math.max(1, size); we.checkMaxRadius(size); @@ -504,7 +507,7 @@ public class UtilityCommands { @CommandPermissions("worldedit.green") @Logging(PLACEMENT) public int green(Actor actor, LocalSession session, EditSession editSession, - @Range(min=1) @Arg(desc = "The radius of the circle to convert in", def = "10") + @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 { @@ -513,10 +516,37 @@ public class UtilityCommands { final boolean onlyNormalDirt = !convertCoarse; final int affected = editSession.green(session.getPlacementPosition(actor), size, onlyNormalDirt); - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print(affected + " surface(s) greened."); return affected; } + private int killMatchingEntities(Integer radius, Actor actor, Supplier func) throws IncompleteRegionException, + MaxChangedBlocksException { + List visitors = new ArrayList<>(); + + 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 { + entities = editSession.getEntities(); + } + visitors.add(new EntityVisitor(entities.iterator(), func.get())); + + int killed = 0; + for (EntityVisitor visitor : visitors) { + Operations.completeLegacy(visitor); + killed += visitor.getAffected(); + } + + session.remember(editSession); + editSession.flushSession(); + return killed; + } + @Command( name = "extinguish", aliases = { "/ex", "/ext", "/extinguish", "ex", "ext" }, @@ -525,7 +555,7 @@ public class UtilityCommands { @CommandPermissions("worldedit.extinguish") @Logging(PLACEMENT) public void extinguish(Actor actor, LocalSession session, EditSession editSession, - @Range(min=1) @Arg(desc = "The radius of the square to remove in", def = "") + @Arg(desc = "The radius of the square to remove in", def = "") Integer radius) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); @@ -534,9 +564,9 @@ public class UtilityCommands { int size = radius != null ? Math.max(1, radius) : defaultRadius; we.checkMaxRadius(size); - Mask mask = BlockTypes.FIRE.toMask(); + Mask mask = new BlockTypeMask(editSession, BlockTypes.FIRE); int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, size); - BBC.VISITOR_BLOCK.send(actor, affected); + actor.print(affected + " block(s) have been removed."); } @Command( @@ -597,6 +627,22 @@ public class UtilityCommands { return killed; } + @Command( + name = "/help", + desc = "Displays help for WorldEdit commands" + ) + @CommandPermissions("worldedit.help") + public void help(Actor actor, + @Switch(name = 's', desc = "List sub-commands of the given command, if applicable") + boolean listSubCommands, + @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 { + PrintCommandHelp.help(command, page, listSubCommands, + we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "//help"); + } + @Command( name = "remove", aliases = { "rem", "rement" }, @@ -607,9 +653,8 @@ public class UtilityCommands { public int remove(Actor actor, @Arg(desc = "The type of entity to remove") EntityRemover remover, - @Range(min=-1) @Arg(desc = "The radius of the cuboid to remove from") + @Arg(desc = "The radius of the cuboid to remove from") int radius) throws WorldEditException { - if (radius < -1) { actor.printError("Use -1 to remove all entities in loaded chunks"); return 0; @@ -621,34 +666,6 @@ public class UtilityCommands { return removed; } - private int killMatchingEntities(Integer radius, Actor actor, Supplier func) throws IncompleteRegionException, MaxChangedBlocksException { - List visitors = new ArrayList<>(); - - 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 { - entities = editSession.getEntities(); - } - visitors.add(new EntityVisitor(entities.iterator(), func.get())); - - int killed = 0; - for (EntityVisitor visitor : visitors) { - Operations.completeLegacy(visitor); - killed += visitor.getAffected(); - } - - BBC.KILL_SUCCESS.send(actor, killed, radius); - - session.remember(editSession); - editSession.flushSession(); - 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 { @@ -663,7 +680,7 @@ public class UtilityCommands { @CommandPermissions("worldedit.calc") public void calc(Actor actor, @Arg(desc = "Expression to evaluate", variable = true) - List input) throws EvaluationException { + List input) { Expression expression; try { expression = Expression.compile(String.join(" ", input)); @@ -672,11 +689,12 @@ public class UtilityCommands { "'%s' could not be parsed as a valid expression", input)); return; } - double result = expression.evaluate( - new double[]{}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout()); - String formatted = Double.isNaN(result) ? "NaN" : formatter.format(result); - TextComponent msg = SubtleFormat.wrap(input + " = ").append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE)); - actor.print(msg); + 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( @@ -690,22 +708,6 @@ public class UtilityCommands { } } - @Command( - name = "/help", - desc = "Displays help for WorldEdit commands" - ) - @CommandPermissions("worldedit.help") - public void help(Actor actor, - @Switch(name = 's', desc = "List sub-commands of the given command, if applicable") - boolean listSubCommands, - @ArgFlag(name = 'p', desc = "The page to retrieve", def = "1") - int page, - @Arg(desc = "The command to retrieve help for", def = "", variable = true) - List commandStr) throws WorldEditException { - PrintCommandHelp.help(commandStr, page, listSubCommands, - we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "//help"); - } - public static List> filesToEntry(final File root, final List files, final UUID uuid) { return Lists.transform(files, input -> { // Keep this functional, as transform is evaluated lazily URI uri = input.toURI(); 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 cd73e2b8b..b6b3bd828 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 @@ -56,11 +56,9 @@ import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.Switch; -@CommandContainer(superTypes = {CommandPermissionsConditionGenerator.Registration.class, CommandQueuedConditionGenerator.Registration.class}) +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class WorldEditCommands { - - private static final DateTimeFormatter dateFormat = DateTimeFormatter - .ofPattern("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; @@ -174,11 +172,10 @@ public class WorldEditCommands { try { ZoneId tz = ZoneId.of(timezone); session.setTimezone(tz); - BBC.TIMEZONE_SET.send(actor, tz.getDisplayName( - TextStyle.FULL, Locale.ENGLISH + actor.print("Timezone set for this session to: " + tz.getDisplayName( + TextStyle.FULL, Locale.ENGLISH )); - BBC.TIMEZONE_DISPLAY - .send(actor, dateFormat.format(ZonedDateTime.now(tz))); + actor.print("The current time in that timezone is: " + dateFormat.format(ZonedDateTime.now(tz))); } catch (ZoneRulesException e) { actor.printError("Invalid timezone"); } @@ -186,7 +183,7 @@ public class WorldEditCommands { @Command( name = "help", - desc = "Displays help for FAWE commands" + desc = "Displays help for WorldEdit commands" ) @SkipQueue @CommandPermissions("worldedit.help") @@ -196,8 +193,8 @@ public class WorldEditCommands { @ArgFlag(name = 'p', desc = "The page to retrieve", def = "1") int page, @Arg(desc = "The command to retrieve help for", def = "", variable = true) - List commandStr) throws WorldEditException { - PrintCommandHelp.help(commandStr, page, listSubCommands, - we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "/worldedit help"); + List command) throws WorldEditException { + PrintCommandHelp.help(command, page, listSubCommands, + we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "/worldedit help"); } } 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 b3e380768..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 @@ -19,20 +19,21 @@ package com.sk89q.worldedit.command.argument; -import static com.google.common.base.Preconditions.checkArgument; -import static com.sk89q.worldedit.util.formatting.text.TextComponent.space; - import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; -import java.util.List; 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; +import static com.sk89q.worldedit.util.formatting.text.TextComponent.space; + public class CommaSeparatedValuesConverter implements ArgumentConverter { public static CommaSeparatedValuesConverter wrap(ArgumentConverter delegate) { 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 bc52d24f6..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 @@ -28,12 +28,13 @@ 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 static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; 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) { 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 620fa50c1..3f877a921 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 @@ -66,8 +66,8 @@ public class AreaPickaxe implements BlockTool { try { for (int x = ox - range; x <= ox + range; ++x) { - for (int z = oz - range; z <= oz + range; ++z) { - for (int y = oy + range; y >= oy - range; --y) { + for (int y = oy - range; y <= oy + range; ++y) { + for (int z = oz - range; z <= oz + range; ++z) { if (initialType.equals(editSession.getBlock(x, y, z))) { continue; } 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 243f2f77e..f29f2be08 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 @@ -70,7 +70,6 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockType; @@ -437,7 +436,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool @Override public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { return act(BrushAction.PRIMARY, player, session); - } + } public BlockVector3 getPosition(EditSession editSession, Player player) { Location loc = player.getLocation(); 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 a9e493564..434e8e1e0 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 @@ -23,7 +23,6 @@ import com.boydti.fawe.config.BBC; 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; @@ -40,11 +39,6 @@ public class DistanceWand extends BrushTool implements DoubleActionTraceTool { super("worldedit.selection.pos"); } - @Override - public boolean canUse(Actor player) { - return player.hasPermission("worldedit.wand"); - } - @Override public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) { Location target = getTarget(player); @@ -74,8 +68,7 @@ public class DistanceWand extends BrushTool implements DoubleActionTraceTool { private Location getTarget(Player player) { Location target; Mask mask = getTraceMask(); - int range = getRange(); - if (range < MAX_RANGE) { + if (this.range > -1) { target = player.getBlockTrace(getRange(), true, mask); } else { target = player.getBlockTrace(MAX_RANGE, false, mask); 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 fafb57405..0493a4125 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 @@ -118,7 +118,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 LocalBlockVectorSet visited = new LocalBlockVectorSet(); final LocalBlockVectorSet queue = new LocalBlockVectorSet(); 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 cfa731504..e2a516430 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 @@ -27,6 +27,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; @@ -56,39 +57,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)) { + 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()) { - eS.setBlock(blockPoint, secondary); + editSession.setBlock(blockPoint, secondary); } else { - eS.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), secondary); + editSession.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), secondary); + } + } catch (MaxChangedBlocksException ignored) { + } finally { + session.remember(editSession); } - return true; - } catch (MaxChangedBlocksException ignored) { - // one block? eat it + } finally { + if (bag != null) { + bag.flushChanges(); } - return false; - + } + 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)) { + 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()) { - eS.setBlock(blockPoint, primary); + editSession.setBlock(blockPoint, primary); } else { - eS.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), primary); + editSession.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), primary); + } + } catch (MaxChangedBlocksException ignored) { + } finally { + session.remember(editSession); } - return true; - } catch (MaxChangedBlocksException ignored) { - // one block? eat it + } finally { + if (bag != null) { + bag.flushChanges(); } - return false; + } + return true; } private Location getTargetFace(Player player) { @@ -99,6 +117,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo } else { target = player.getBlockTrace(MAX_RANGE, false, mask); } + if (target == null) { player.printError(BBC.NO_BLOCK.s()); return null; 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 1bad0a30d..64193e805 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 @@ -24,6 +24,7 @@ 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.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.Location; @@ -33,6 +34,8 @@ 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. */ 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 ca4b65c26..c5c8ecf6a 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 @@ -84,4 +84,36 @@ public class RecursivePickaxe implements BlockTool { return true; } + + private static void recurse(Platform server, EditSession editSession, World world, BlockVector3 pos, + BlockVector3 origin, double size, BlockType initialType, Set visited) throws MaxChangedBlocksException { + + final double distanceSq = origin.distanceSq(pos); + if (distanceSq > size*size || visited.contains(pos)) { + return; + } + + visited.add(pos); + + if (editSession.getBlock(pos).getBlockType() != initialType) { + return; + } + + 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), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(0, 0, 1), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(0, 0, -1), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(0, 1, 0), + origin, size, initialType, visited); + recurse(server, editSession, world, pos.add(0, -1, 0), + origin, size, initialType, visited); + } } 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 1e783df55..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 @@ -44,7 +44,7 @@ public class ClipboardBrush implements Brush { this.ignoreAirBlocks = ignoreAirBlocks; this.usingOrigin = usingOrigin; this.pasteBiomes = false; - this.pasteEntities = true; + this.pasteEntities = false; this.sourceMask = null; } 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 ac0736cc0..2901baa66 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,7 +23,12 @@ 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 java.util.LinkedHashSet; +import java.util.Set; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.util.collection.LocatedBlockList; import com.sk89q.worldedit.world.block.BlockTypes; public class GravityBrush implements Brush { @@ -48,12 +53,15 @@ public class GravityBrush implements Brush { if (y != freeSpot) { editSession.setBlock((int)x, (int)y, (int)z, BlockTypes.AIR.getDefaultState()); editSession.setBlock((int)x, (int)freeSpot, (int)z, block); - } + } freeSpot = y + 1; + } } } + + column.clear(); + removedBlocks.clear(); } } - } } 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 5afe27446..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 @@ -19,8 +19,6 @@ package com.sk89q.worldedit.command.util; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.ListenableFuture; @@ -42,6 +40,9 @@ 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); 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 91ca575bd..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 @@ -19,7 +19,6 @@ package com.sk89q.worldedit.command.util; -import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableSet; import org.enginehub.piston.Command; import org.enginehub.piston.gen.CommandConditionGenerator; @@ -28,6 +27,8 @@ 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 final class CommandPermissionsConditionGenerator implements CommandConditionGenerator { 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 1385b2337..0b5fc1719 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 @@ -20,12 +20,12 @@ package com.sk89q.worldedit.command.util; import com.boydti.fawe.util.TaskManager; - -import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.entity.metadata.EntityProperties; import com.sk89q.worldedit.function.EntityFunction; import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; import java.util.regex.Pattern; /** 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 64856a89e..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 @@ -24,8 +24,6 @@ import org.enginehub.piston.Command; import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.Key; -import java.lang.annotation.Annotation; -import java.util.Optional; import java.util.Set; public class PermissionCondition implements Command.Condition { 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 4f3d0dc95..30c03771f 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 @@ -303,14 +303,6 @@ public interface Player extends Entity, Actor { */ void setPosition(Vector3 pos, float pitch, float yaw); - /** - * Move the player. - * - * @param pos where to move them - */ - @Override - void setPosition(Vector3 pos); - /** * Sends a fake block to the client. * 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 17d8d748a..09f070f42 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 @@ -18,8 +18,6 @@ */ 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; @@ -27,6 +25,8 @@ 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. */ 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 7b46c3fc1..ac0bcdb2a 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 @@ -32,6 +32,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 @@ -48,19 +49,36 @@ public final class MaskFactory extends AbstractFactory { * @param worldEdit the WorldEdit instance */ public MaskFactory(WorldEdit worldEdit) { - super(worldEdit, new DefaultMaskParser(worldEdit)); + super(worldEdit, new DefaultMaskParser(worldEdit)); + /* + super(worldEdit, new BlocksMaskParser(worldEdit)); -// register(new ExistingMaskParser(worldEdit)); -// register(new SolidMaskParser(worldEdit)); -// register(new LazyRegionMaskParser(worldEdit)); -// register(new RegionMaskParser(worldEdit)); -// register(new OffsetMaskParser(worldEdit)); -// register(new NoiseMaskParser(worldEdit)); -// register(new BlockStateMaskParser(worldEdit)); -// register(new NegateMaskParser(worldEdit)); -// register(new ExpressionMaskParser(worldEdit)); - register(new BlockCategoryMaskParser(worldEdit)); // TODO implement in DefaultMaskParser -// register(new BiomeMaskParser(worldEdit)); + register(new ExistingMaskParser(worldEdit)); + register(new SolidMaskParser(worldEdit)); + register(new LazyRegionMaskParser(worldEdit)); + register(new RegionMaskParser(worldEdit)); + register(new OffsetMaskParser(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)); + */ + + + } + + @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 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 d750ff860..6bf92d383 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 @@ -40,16 +40,19 @@ public final class PatternFactory extends AbstractFactory { * @param worldEdit the WorldEdit instance */ public PatternFactory(WorldEdit worldEdit) { - super(worldEdit, new DefaultPatternParser(worldEdit)); + super(worldEdit, new DefaultPatternParser(worldEdit)); + /* + super(worldEdit, new SingleBlockPatternParser(worldEdit)); // split and parse each sub-pattern -// register(new RandomPatternParser(worldEdit)); + register(new RandomPatternParser(worldEdit)); // individual patterns -// register(new ClipboardPatternParser(worldEdit)); -// register(new TypeOrStateApplyingPatternParser(worldEdit)); -// register(new RandomStatePatternParser(worldEdit)); - register(new BlockCategoryPatternParser(worldEdit)); // TODO implement in pattern parser + register(new ClipboardPatternParser(worldEdit)); + register(new TypeOrStateApplyingPatternParser(worldEdit)); + register(new RandomStatePatternParser(worldEdit)); + */ + register(new BlockCategoryPatternParser(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 c944ba359..175b68449 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,8 @@ package com.sk89q.worldedit.extension.factory.parser; +import com.google.common.collect.Maps; + import com.boydti.fawe.command.SuggestInputParseException; import com.boydti.fawe.config.BBC; import com.boydti.fawe.jnbt.JSON2NBT; @@ -35,7 +37,7 @@ import com.sk89q.worldedit.blocks.BaseItem; 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.command.util.SuggestionHelper; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.DisallowedUsageException; import com.sk89q.worldedit.extension.input.InputParseException; @@ -61,6 +63,8 @@ import com.sk89q.worldedit.world.registry.LegacyMapper; import java.util.Arrays; import java.util.Locale; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.entity.EntityTypes; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -111,6 +115,8 @@ public class DefaultBlockParser extends InputParser { } } + private static String[] EMPTY_STRING_ARRAY = {}; + /** * Backwards compatibility for wool colours in block syntax. * @@ -162,6 +168,71 @@ public class DefaultBlockParser extends InputParser { } } + 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 + // Parse the block data (optional) + for (String parseableData : stateProperties) { + try { + String[] parts = parseableData.split("="); + if (parts.length != 2) { + throw new NoMatchException("Bad state format in " + parseableData); + } + + @SuppressWarnings("unchecked") + 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.getId()); + } else { + WorldEdit.logger.warn("Unknown property " + parts[0] + " for block " + type.getId()); + } + return Maps.newHashMap(); + } + if (blockStates.containsKey(propertyKey)) { + throw new NoMatchException("Duplicate property " + parts[0]); + } + Object value; + try { + value = propertyKey.getValueFor(parts[1]); + } catch (IllegalArgumentException e) { + throw new NoMatchException("Unknown value " + parts[1] + " for state " + parts[0]); + } + + blockStates.put(propertyKey, value); + } catch (NoMatchException e) { + throw e; // Pass-through + } catch (Exception e) { + WorldEdit.logger.warn("Unknown state '" + parseableData + "'", e); + throw new NoMatchException("Unknown state '" + parseableData + "'"); + } + } + } + + return blockStates; + } + + @Override + public Stream getSuggestions(String input) { + final int idx = input.lastIndexOf('['); + if (idx < 0) { + return SuggestionHelper.getNamespacedRegistrySuggestions(BlockType.REGISTRY, input); + } + 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 { String[] blockAndExtraData = input.trim().split("\\|", 2); blockAndExtraData[0] = woolMapper(blockAndExtraData[0]); @@ -193,7 +264,7 @@ public class DefaultBlockParser extends InputParser { state = LegacyMapper.getInstance().getBlockFromLegacy(type.getLegacyCombinedId() >> 4, data); } } - } catch (NumberFormatException e) { + } catch (NumberFormatException ignored) { } } @@ -206,6 +277,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()) { @@ -288,6 +366,10 @@ public class DefaultBlockParser extends InputParser { } } } + // this should be impossible but IntelliJ isn't that smart + if (blockType == null) { + throw new NoMatchException("Does not match a valid block type: '" + input + "'"); + } if (blockAndExtraData.length > 1 && blockAndExtraData[1].startsWith("{")) { String joined = StringMan.join(Arrays.copyOfRange(blockAndExtraData, 1, blockAndExtraData.length), "|"); @@ -322,6 +404,7 @@ public class DefaultBlockParser extends InputParser { break; } } + mobName = ent.getId(); if (!worldEdit.getPlatformManager().queryCapability(Capability.USER_COMMANDS).isValidMobType(mobName)) { String finalMobName = mobName.toLowerCase(Locale.ROOT); throw new SuggestInputParseException("Unknown mob type '" + mobName + "'", mobName, () -> Stream.of(MobType.values()) 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 21fc46c4f..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; 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 026aa712f..6e9a5b0ef 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,8 @@ 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; 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 324bf0857..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; 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 fa49aea32..277ac636c 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,8 @@ 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; import java.util.stream.Stream; 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 4fafcfaea..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; 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 757235940..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 @@ -30,6 +30,7 @@ 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 java.util.HashMap; import java.util.Map; import java.util.stream.Stream; 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 index 046417574..8262d0696 100644 --- 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 @@ -19,45 +19,12 @@ package com.sk89q.worldedit.extension.platform; -import com.boydti.fawe.object.exception.FaweException; -import com.boydti.fawe.object.task.SimpleAsyncNotifyQueue; -import com.boydti.fawe.util.TaskManager; -import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.internal.cui.CUIEvent; import java.io.File; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; public abstract class AbstractNonPlayerActor implements Actor { - private final ConcurrentHashMap meta = new ConcurrentHashMap<>(); - - @Override - public Map getRawMeta() { - return meta; - } - - // Queue for async tasks - private AtomicInteger runningCount = new AtomicInteger(); - private SimpleAsyncNotifyQueue asyncNotifyQueue = new SimpleAsyncNotifyQueue( - (thread, throwable) -> { - while (throwable.getCause() != null) { - throwable = throwable.getCause(); - } - if (throwable instanceof WorldEditException) { - printError(throwable.getLocalizedMessage()); - } else { - FaweException fe = FaweException.get(throwable); - if (fe != null) { - printError(fe.getMessage()); - } else { - throwable.printStackTrace(); - } - } - }); - @Override public boolean canDestroyBedrock() { return true; @@ -81,35 +48,4 @@ public abstract class AbstractNonPlayerActor implements Actor { @Override public void dispatchCUIEvent(CUIEvent event) { } - - /** - * Run a task either async, or on the current thread - * - * @param ifFree - * @param checkFree Whether to first check if a task is running - * @param async - * @return false if the task was ran or queued - */ - @Override - public boolean runAction(Runnable ifFree, boolean checkFree, boolean async) { - if (checkFree) { - if (runningCount.get() != 0) { - return false; - } - } - Runnable wrapped = () -> { - try { - runningCount.addAndGet(1); - ifFree.run(); - } finally { - runningCount.decrementAndGet(); - } - }; - if (async) { - asyncNotifyQueue.queue(wrapped); - } else { - TaskManager.IMP.taskNow(wrapped, false); - } - return true; - } } 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 12ba7e815..545476732 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,13 +19,14 @@ package com.sk89q.worldedit.extension.platform; +import com.sk89q.worldedit.EditSession; + import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.task.SimpleAsyncNotifyQueue; import com.boydti.fawe.regions.FaweMaskManager; import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.WEManager; -import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; @@ -45,6 +46,8 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.ConvexPolyhedralRegionSelector; + +import javax.annotation.Nullable; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.regions.selector.CylinderRegionSelector; import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector; @@ -70,7 +73,6 @@ import java.text.NumberFormat; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import javax.annotation.Nullable; import org.enginehub.piston.inject.InjectedValueAccess; import org.jetbrains.annotations.NotNull; @@ -249,7 +251,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { if (!lastState) { lastState = BlockTypeUtil.centralBottomLimit(state) != 1; continue; - } + } if (freeStart == -1) { freeStart = level + BlockTypeUtil.centralTopLimit(state); } else { @@ -257,13 +259,13 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { double space = level + bottomLimit - freeStart; if (space >= height) { setPosition(Vector3.at(x + 0.5, freeStart, z + 0.5)); - return true; - } + return true; + } // Not enough room, reset the free position if (bottomLimit != 1) { freeStart = -1; - } - } + } + } } else { freeStart = -1; lastState = true; @@ -414,7 +416,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { session.setBlock(spot, BlockTypes.GLASS.getDefaultState()); } catch (MaxChangedBlocksException ignored) { } - } + } } else { setFlying(true); } @@ -477,6 +479,23 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { return getBlockTrace(range, 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 Location getSolidBlockTrace(int range) { TargetBlock tb = new TargetBlock(this, range, 0.2); @@ -541,33 +560,17 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { 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; - } + return false; + } if (!advanceToFree(hitBlox)) { - return false; + return false; } Location foundBlock = hitBlox.getCurrentBlock(); @@ -576,7 +579,6 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { return true; } - return 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 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/extension/platform/PlatformManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java index 0235273a2..637991687 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,45 +321,45 @@ public class PlatformManager { if (!(actor instanceof Player)) { return; } - Player player = (Player) actor; - LocalSession session = worldEdit.getSessionManager().get(actor); + 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 { + try { Vector3 vector = location.toVector(); VirtualWorld virtual = session.getVirtualWorld(); if (virtual != null) { virtual.handleBlockInteract(player, vector.toBlockPoint(), event); if (event.isCancelled()) return; - } + } 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)) { + final BlockTool superPickaxe = session.getSuperPickaxe(); + if (superPickaxe != null && superPickaxe.canUse(player)) { player.runAction(() -> reset(superPickaxe) .actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location), false, true); event.setCancelled(true); - return; + return; + } } - } Tool tool = session.getTool(player); if (tool instanceof DoubleActionBlockTool && tool.canUse(player)) { player.runAction(() -> reset(((DoubleActionBlockTool) tool)) .actSecondary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location), false, true); - event.setCancelled(true); - } + event.setCancelled(true); + } - } else if (event.getType() == Interaction.OPEN) { + } else if (event.getType() == Interaction.OPEN) { Tool tool = session.getTool(player); if (tool instanceof BlockTool && tool.canUse(player)) { if (player.checkAction()) { @@ -367,20 +367,20 @@ public class PlatformManager { BlockTool blockTool = (BlockTool) tool; if (!(tool instanceof BrushTool)) { blockTool = reset(blockTool); - } + } blockTool.actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location); }, false, true); event.setCancelled(true); } - } - } + } + } } catch (Throwable e) { handleThrowable(e, actor); - } finally { - Request.reset(); + } finally { + Request.reset(); + } } - } public void handleThrowable(Throwable e, Actor actor) { FaweException faweException = FaweException.get(e); @@ -409,53 +409,29 @@ public class PlatformManager { try { switch (event.getInputType()) { case PRIMARY: { - if (getConfiguration().navigationWandMaxDistance > 0 && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().navigationWand)) { - if (!player.hasPermission("worldedit.navigation.jumpto.tool")) { - return; - } - Location pos = player.getSolidBlockTrace(getConfiguration().navigationWandMaxDistance); - if (pos != null) { - player.findFreePosition(pos); - } else { - player.printError(BBC.NO_BLOCK.s()); - } - - event.setCancelled(true); - return; - } Tool tool = session.getTool(player); if (tool instanceof DoubleActionTraceTool && tool.canUse(player)) { player.runAsyncIfFree(() -> reset((DoubleActionTraceTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session)); - event.setCancelled(true); - return; - } + event.setCancelled(true); + } + return; + } break; } case SECONDARY: { - if (getConfiguration().navigationWandMaxDistance > 0 && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().navigationWand)) { - if (!player.hasPermission("worldedit.navigation.thru.tool")) { - return; - } - - if (!player.passThroughForwardWall(40)) { - player.printError(BBC.NAVIGATION_WAND_ERROR.s()); - } - - event.setCancelled(true); - return; - } Tool tool = session.getTool(player); if (tool instanceof TraceTool && tool.canUse(player)) { //todo this needs to be fixed so the event is canceled after actPrimary is used and returns true player.runAction(() -> reset((TraceTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session), false, true); - event.setCancelled(true); - return; - } + event.setCancelled(true); + } + return; + } break; } 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 872a48674..ce8c8b0bd 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 @@ -221,4 +221,9 @@ public class PlayerProxy extends AbstractPlayerActor { public Player getBasePlayer() { return basePlayer; } + + @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/Extent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java index 7d6be3084..418753116 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -572,7 +572,7 @@ public interface Extent extends InputExtent, OutputExtent { * @throws MaxChangedBlocksException thrown if too many blocks are changed */ default > int replaceBlocks(Region region, Set filter, B replacement) throws MaxChangedBlocksException { - return replaceBlocks(region, filter, new BlockPattern(replacement)); + return replaceBlocks(region, filter, (Pattern) replacement); } /** 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 a6cbab8f5..08abcc2cb 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 @@ -29,7 +29,6 @@ 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; @@ -74,26 +73,6 @@ public class ExtentBuffer extends AbstractBufferingExtent { return Optional.empty(); } - @Override - public BlockState getBlock(BlockVector3 position) { - if (mask.test(position)) { - return getOrDefault(position).toImmutableState(); - } - 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))); - } - @Override public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { if (mask.test(location)) { 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 2dfff0aef..f060bf90e 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 @@ -31,12 +31,12 @@ 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.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.regions.AbstractFlatRegion; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; import java.util.Iterator; @@ -84,7 +84,6 @@ 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(); @@ -189,7 +188,7 @@ public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pat * @return a region */ public Region asRegion() { - return new AbstractRegion(null) { + return new AbstractFlatRegion(null) { @Override public BlockVector3 getMinimumPoint() { return min != null ? min : BlockVector3.ZERO; @@ -220,6 +219,7 @@ public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pat return buffer.keySet().iterator(); } + @Override public Iterable asFlatRegion() { return biomeBuffer.keySet(); } 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 9fa1bb062..974bf7616 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 @@ -24,6 +24,7 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.math.BlockVector3; import java.io.Closeable; import java.io.IOException; +import java.util.OptionalInt; import java.util.UUID; import java.util.function.Function; @@ -44,6 +45,15 @@ public interface ClipboardReader extends Closeable { return read(UUID.randomUUID()); } + /** + * Get the DataVersion from a file (if possible). + * + * @return The data version, or empty + */ + default OptionalInt getDataVersion() { + return OptionalInt.empty(); + } + default Clipboard read(UUID uuid) throws IOException { return read(uuid, DiskOptimizedClipboard::new); } 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 c59394122..8fd0d9303 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,8 +19,9 @@ package com.sk89q.worldedit.extent.clipboard.io; -import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableList; + +import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.jnbt.ByteArrayTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; @@ -59,6 +60,8 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.HashSet; +import java.util.Set; /** * Reads schematic files that are compatible with MCEdit and other editors. @@ -176,7 +179,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<>(); @@ -206,6 +210,11 @@ public class MCEditSchematicReader extends NBTSchematicReader { if (values.isEmpty()) { t = null; } + if (values.isEmpty()) { + t = null; + } else { + t = new CompoundTag(values); + } if (fixer != null && t != null) { t = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, t, -1); @@ -221,9 +230,8 @@ public class MCEditSchematicReader extends NBTSchematicReader { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); clipboard.setOrigin(origin); - // Don't log a torrent of errors - int failedBlockSets = 0; + 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) { @@ -242,18 +250,7 @@ public class MCEditSchematicReader extends NBTSchematicReader { 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 } } } 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 737a2c0be..0f069e689 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 @@ -56,6 +56,8 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extension.platform.Capability; import net.jpountz.lz4.LZ4BlockInputStream; import net.jpountz.lz4.LZ4BlockOutputStream; import org.slf4j.Logger; @@ -63,7 +65,6 @@ import org.slf4j.LoggerFactory; import java.io.DataInputStream; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -72,6 +73,8 @@ import java.util.UUID; import java.util.function.Function; import static com.google.common.base.Preconditions.checkNotNull; +import com.sk89q.worldedit.world.storage.NBTConversions; +import java.util.OptionalInt; /** * Reads schematic files using the Sponge Schematic Specification. @@ -96,6 +99,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { private int offsetX, offsetY, offsetZ; private char[] palette, biomePalette; private BlockVector3 min = BlockVector3.ZERO; + private int schematicVersion = -1; /** @@ -210,7 +214,58 @@ public class SpongeSchematicReader extends NBTSchematicReader { } @Override - public Clipboard read(UUID uuid, Function createOutput) throws IOException { + public Clipboard read() throws IOException { + CompoundTag schematicTag = getBaseTag(); + Map schematic = schematicTag.getValue(); + + final Platform platform = WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.WORLD_EDITING); + int liveDataVersion = platform.getDataVersion(); + + 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 (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.", + dataVersion, liveDataVersion); + } else if (dataVersion < liveDataVersion) { + fixer = platform.getDataFixer(); + if (fixer != null) { + log.debug("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.", + dataVersion, liveDataVersion); + } 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); + } + 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(); + } + } + + @Override + public Clipboard getBaseTag(UUID uuid, Function createOutput) throws IOException { StreamDelegate root = createDelegate(); inputStream.readNamedTagLazy(root); if (blocks != null) blocks.close(); @@ -349,6 +404,106 @@ 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); + 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."); + } + + for (Entry palettePart : paletteTag.getValue().entrySet()) { + 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 :" + key + + " in palette. Are you missing a mod or using a schematic made in a newer version of Minecraft?"); + } + Tag idTag = palettePart.getValue(); + if (!(idTag instanceof IntTag)) { + 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; + BlockVector2 min = clipboard.getMinimumPoint().toBlockVector2(); + while (biomeJ < biomes.length) { + bVal = 0; + varIntLength = 0; + + while (true) { + bVal |= (biomes[biomeJ] & 127) << (varIntLength++ * 7); + if (varIntLength > 5) { + throw new IOException("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(min.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(); + 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); + 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 497aba25b..3ea7ed88a 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 @@ -20,13 +20,16 @@ package com.sk89q.worldedit.extent.clipboard.io; import com.boydti.fawe.jnbt.streamer.IntValueReader; + +import com.google.common.collect.Maps; import com.boydti.fawe.object.FaweOutputStream; import com.boydti.fawe.object.clipboard.LinearClipboard; import com.boydti.fawe.util.IOUtil; -import com.google.common.collect.Maps; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntArrayTag; import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.FloatTag; +import com.sk89q.jnbt.DoubleTag; import com.sk89q.jnbt.NBTConstants; import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.jnbt.StringTag; @@ -61,7 +64,9 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import com.sk89q.worldedit.math.Vector3; import java.util.Objects; +import com.sk89q.worldedit.util.Location; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; @@ -334,6 +339,90 @@ public class SpongeSchematicWriter implements ClipboardWriter { schematic.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities)); } + 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())); + 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()); + 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/extent/reorder/ChunkBatchingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java index bf98dc45a..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 @@ -25,7 +25,6 @@ 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; 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 739b19da9..01b4a014d 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 @@ -18,8 +18,6 @@ */ package com.sk89q.worldedit.extent.transform; - -import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.worldedit.util.Direction.ASCENDING_EAST; import static com.sk89q.worldedit.util.Direction.ASCENDING_NORTH; import static com.sk89q.worldedit.util.Direction.ASCENDING_SOUTH; @@ -69,8 +67,11 @@ import java.util.Map; import javax.annotation.Nullable; import com.sk89q.worldedit.world.block.BlockTypesCache; +import java.util.HashMap; import org.jetbrains.annotations.NotNull; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Transforms blocks themselves (but not their position) according to a * given transform. 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); + } } 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 cb761de44..0b60c5299 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 @@ -59,23 +59,23 @@ public class ForestGenerator implements RegionFunction { case BlockID.DIRT: case BlockID.PODZOL: case BlockID.COARSE_DIRT: - return treeType.generate(editSession, position.add(0, 1, 0)); + return treeType.generate(editSession, position.add(0, 1, 0)); default: - if (t.getMaterial().isReplacedDuringPlacement()) { - // since the implementation's tree generators generally don't generate in non-air spots, - // we trick editsession history here in the first call - editSession.setBlock(position, BlockTypes.AIR.getDefaultState()); - // and then trick the generator here by directly setting into the world - editSession.getWorld().setBlock(position, BlockTypes.AIR.getDefaultState()); - // so that now the generator can generate the tree - boolean success = treeType.generate(editSession, position); - if (!success) { - editSession.setBlock(position, block); // restore on failure - } - return success; - } else { // Trees won't grow on this! - return false; + if (t.getMaterial().isReplacedDuringPlacement()) { + // since the implementation's tree generators generally don't generate in non-air spots, + // we trick editsession history here in the first call + editSession.setBlock(position, BlockTypes.AIR.getDefaultState()); + // and then trick the generator here by directly setting into the world + editSession.getWorld().setBlock(position, BlockTypes.AIR.getDefaultState()); + // so that now the generator can generate the tree + boolean success = treeType.generate(editSession, position); + if (!success) { + editSession.setBlock(position, block); // restore on failure } + return success; + } else { // Trees won't grow on this! + return false; + } } } } 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); } /** 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 37ba15339..7f850d5e2 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 @@ -22,8 +22,8 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.EvaluationException; 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.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 eab959f1d..051e4692a 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 @@ -22,8 +22,8 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.EvaluationException; import com.sk89q.worldedit.internal.expression.ExpressionException; -import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; import com.sk89q.worldedit.math.BlockVector2; import java.util.function.IntSupplier; import javax.annotation.Nullable; 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 767820c31..b9e490d11 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 @@ -36,16 +36,21 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; 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.RegionMaskTestFunction; +import com.sk89q.worldedit.function.biome.ExtentBiomeCopy; import com.sk89q.worldedit.function.RegionMaskingFilter; import com.sk89q.worldedit.function.entity.ExtentEntityCopy; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.mask.Mask2D; import com.sk89q.worldedit.function.visitor.EntityVisitor; import com.sk89q.worldedit.function.visitor.IntersectRegionFunction; import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.function.visitor.FlatRegionVisitor; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Identity; import com.sk89q.worldedit.math.transform.Transform; @@ -78,7 +83,7 @@ public class ForwardExtentCopy implements Operation { private RegionFunction sourceFunction = null; private Transform transform = new Identity(); private Transform currentTransform = null; - private int affected; + private int affectedBlocks; private RegionFunction filterFunction; /** @@ -94,6 +99,10 @@ public class ForwardExtentCopy implements Operation { public ForwardExtentCopy(Extent source, Region region, Extent destination, BlockVector3 to) { this(source, region, region.getMinimumPoint(), destination, to); } + private FlatRegionVisitor lastBiomeVisitor; + private EntityVisitor lastEntityVisitor; + private int affectedBiomeCols; + private int affectedEntities; /** * Create a new copy. @@ -267,7 +276,7 @@ public class ForwardExtentCopy implements Operation { * @return the number of affected */ public int getAffected() { - return affected; + return affectedBlocks + affectedBiomeCols + affectedEntities; } @Override @@ -275,6 +284,14 @@ public class ForwardExtentCopy implements Operation { if (currentTransform == null) { currentTransform = transform; } + if (lastBiomeVisitor != null) { + affectedBiomeCols += lastBiomeVisitor.getAffected(); + lastBiomeVisitor = null; + } + if (lastEntityVisitor != null) { + affectedEntities += lastEntityVisitor.getAffected(); + lastEntityVisitor = null; + } Extent finalDest = destination; BlockVector3 translation = to.subtract(from); @@ -405,7 +422,21 @@ public class ForwardExtentCopy implements Operation { @Override public void addStatusMessages(List messages) { StringBuilder msg = new StringBuilder(); - msg.append(affected).append(" objects(s)"); + 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()); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Range.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Range.java deleted file mode 100644 index be4bdc773..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/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.internal.annotation; - -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/internal/annotation/Validate.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Validate.java deleted file mode 100644 index fa1e43039..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/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.internal.annotation; - -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, ElementType.METHOD}) -public @interface Validate { - - /** - * An optional regular expression that must match the string. - * - * @see Pattern regular expression class - * @return the pattern - */ - String value() default ""; - -} 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 b015a5658..7033b5828 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 @@ -19,8 +19,6 @@ package com.sk89q.worldedit.internal.command.exception; -import static com.google.common.base.Preconditions.checkNotNull; - import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.DisallowedItemException; import com.sk89q.worldedit.EmptyClipboardException; @@ -29,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; @@ -47,6 +46,8 @@ import java.util.regex.Pattern; import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.UsageException; +import static com.google.common.base.Preconditions.checkNotNull; + /** * converts WorldEdit exceptions and converts them into {@link CommandException}s. */ 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 db404f03e..14a3edd0f 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,26 +19,28 @@ 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 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 com.sk89q.worldedit.session.request.Request; +import org.antlr.v4.runtime.tree.ParseTreeWalker; import java.util.ArrayDeque; -import java.util.HashMap; + +import java.lang.invoke.MethodHandle; import java.util.List; -import java.util.Map; +import java.util.Objects; import java.util.concurrent.ExecutionException; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -68,61 +70,64 @@ 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 { private static final ThreadLocal> instance = ThreadLocal.withInitial(ArrayDeque::new); - 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 Map variables = new HashMap<>(); + private final SlotTable slots = new SlotTable(); + private final List providedSlots; private Variable[] variableArray; - private RValue root; - private final Functions functions = new Functions(); + private ExpressionParser.AllStatementsContext root; + private final SetMultimap functions = Functions.getFunctionMap(); private ExpressionEnvironment environment; public static Expression compile(String expression, String... variableNames) throws ExpressionException { return new Expression(expression, variableNames); } + private Expression(String expression, String... variableNames) throws ExpressionException { + 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) { + slots.initVariable(variableName) + .orElseThrow(() -> new ExpressionException(-1, + "Tried to overwrite identifier '" + variableName + "'")); + } + this.providedSlots = ImmutableList.copyOf(variableNames); + + 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 Expression(double constant) { root = new Constant(0, constant); } - private Expression(String expression, String... variableNames) throws ExpressionException { - this(Lexer.tokenize(expression), variableNames); - } - - private Expression(List tokens, String... variableNames) throws ExpressionException { - - 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)); - - variableArray = new Variable[variableNames.length]; - for (int i = 0; i < variableNames.length; i++) { - if (variables.containsKey(variableNames[i])) { - throw new ExpressionException(-1, "Tried to overwrite identifier '" + variableNames[i] + "'"); - } - Variable var = new Variable(0); - variables.put(variableNames[i], var); - variableArray[i] = var; - } - - root = Parser.parse(tokens, this); - } - public double evaluate(double x, double y, double z) throws EvaluationException { return evaluateTimeout(WorldEdit.getInstance().getConfiguration().calculationTimeout, x, y, z); } @@ -157,10 +162,19 @@ public class Expression { return root.getValue(); } for (int i = 0; i < values.length; ++i) { - Variable var = variableArray[i]; - var.value = values[i]; + String slotName = providedSlots.get(i); + LocalSlot.Variable slot = slots.getVariable(slotName) + .orElseThrow(() -> new EvaluationException(-1, + "Tried to assign to non-variable " + slotName + ".")); + + slot.setValue(values[i]); } - return evaluateFinal(timeout); + + // evaluation exceptions are thrown out of this method + if (timeout < 0) { + return evaluateRoot(); + } + return evaluateRootTimed(timeout); } private double evaluateFinal(int timeout) throws EvaluationException { @@ -175,6 +189,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(); @@ -182,12 +197,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(); @@ -197,12 +214,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); } } @@ -210,14 +223,18 @@ 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 + } + + public SlotTable getSlots() { + return slots; } public RValue getRoot() { @@ -229,15 +246,6 @@ 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 static Expression getInstance() { return instance.get().peek(); } @@ -253,10 +261,6 @@ public class Expression { foo.pop(); } - 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/IdentifierToken.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/IdentifierToken.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LexerErrorListener.java index 4a840f754..cb4b41ce5 100644 --- 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/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; -/** - * An identifier. - */ -public class IdentifierToken extends Token { - - public final String value; - - public IdentifierToken(int position, String 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 'i'; + 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 "IdentifierToken(" + 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/ParserErrorListener.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ParserErrorListener.java new file mode 100644 index 000000000..937c00154 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ParserErrorListener.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.internal.expression; + +import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; + +class ParserErrorListener extends BaseErrorListener { + @Override + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + throw new ParserException(charPositionInLine, msg); + } +} 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/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 09ec8df2e..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Function.java +++ /dev/null @@ -1,124 +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 { } - - public final Method method; - public final RValue[] args; - - public Function(int position, Method method, RValue... args) { - super(position); - this.method = method; - this.method.setAccessible(true); - 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/internal/registry/InputParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java index 3e490d8ca..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 @@ -35,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 5aa25daaa..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 @@ -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); } 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 7be6b4be3..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java +++ /dev/null @@ -1,188 +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 org.enginehub.piston.annotation.Command; -import com.sk89q.worldedit.command.util.CommandPermissions; -import com.sk89q.minecraft.util.commands.NestedCommand; -import com.sk89q.worldedit.command.*; - -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; - -@SuppressWarnings("UseOfSystemOutOrSystemErr") -public final class DocumentationPrinter { - - private 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!"); - } - - private static List> getCommandClasses(File dir) { - List> classes = new ArrayList<>(); - - classes.add(BiomeCommands.class); - classes.add(ChunkCommands.class); - classes.add(ClipboardCommands.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; - } - - 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 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.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 void writeBukkitYAML() - throws IOException { - try (FileOutputStream stream = new FileOutputStream("plugin.yml")) { - PrintStream print = new PrintStream(stream); - writeBukkitYAML(print); - } - } - - 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."); - } - -} 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 deleted file mode 100644 index 46fa66e73..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BitMath.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.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/BlockVector2.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java index 507293cd4..84fcace71 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 @@ -599,5 +599,4 @@ public class BlockVector2 { public String toString() { return "(" + x + ", " + z + ")"; } - } 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 adf2d3f1c..0e57cc00c 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 @@ -18,8 +18,6 @@ */ package com.sk89q.worldedit.math; - -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; @@ -28,6 +26,8 @@ import static com.sk89q.worldedit.math.BitMath.unpackZ; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.transform.AffineTransform; + +import static com.google.common.base.Preconditions.checkArgument; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -122,6 +122,11 @@ public abstract class BlockVector3 { return new MutableBlockVector3(x, y, z); } + public long toLongPackedForm() { + checkLongPackable(this); + return (x & BITS_26) | ((z & BITS_26) << 26) | (((y & (long) BITS_12) << (26 + 26))); + } + public MutableBlockVector3 mutX(double x) { return new MutableBlockVector3((int) x, getY(), getZ()); } @@ -150,11 +155,6 @@ public abstract class BlockVector3 { return BlockVector3.at(getX(), getY(), getZ()); } - public long toLongPackedForm() { - checkLongPackable(this); - return (getX() & BITS_26) | ((getZ() & BITS_26) << 26) | (((getY() & (long) BITS_12) << (26 + 26))); - } - /** * Get the X coordinate. * 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 534a772c1..cc6bdc320 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 @@ -346,5 +346,13 @@ public class AffineTransform implements Transform, Serializable { 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); } + /** + * 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; + } + } 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/regions/AbstractFlatRegion.java similarity index 69% 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/regions/AbstractFlatRegion.java index 44cc70665..a2641d242 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/regions/AbstractFlatRegion.java @@ -17,28 +17,24 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.internal.expression.lexer.tokens; +package com.sk89q.worldedit.regions; -/** - * A number. - */ -public class NumberToken extends Token { +import com.sk89q.worldedit.world.World; - public final double value; +public abstract class AbstractFlatRegion extends AbstractRegion implements FlatRegion { - public NumberToken(int position, double value) { - super(position); - this.value = value; + protected AbstractFlatRegion(World world) { + super(world); } @Override - public char id() { - return '0'; + public int getMinimumY() { + return getMinimumPoint().getBlockY(); } @Override - public String toString() { - return "NumberToken(" + value + ")"; + public int getMaximumY() { + return getMaximumPoint().getBlockY(); } } 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 893ea83b7..eb62a3b7b 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 @@ -21,8 +21,8 @@ package com.sk89q.worldedit.regions.shape; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.internal.expression.ExpressionEnvironment; import com.sk89q.worldedit.math.MutableVector3; import com.sk89q.worldedit.math.Vector3; 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 bf64e4e12..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 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; - -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 com.sk89q.worldedit.scripting.RhinoContextFactory; - -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-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java index f91c34480..14450054e 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 @@ -39,6 +39,7 @@ import com.sk89q.worldedit.session.storage.JsonFileSessionStore; import com.sk89q.worldedit.session.storage.SessionStore; import com.sk89q.worldedit.session.storage.VoidStore; import com.sk89q.worldedit.util.concurrency.EvenMoreExecutors; +import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.item.ItemType; @@ -200,6 +201,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; } 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()); } 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 61cfb57a5..42d608b7d 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,8 +19,9 @@ package com.sk89q.worldedit.util.eventbus; -import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.HashMultimap; + +import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.Multimap; import com.google.common.collect.SetMultimap; import org.slf4j.Logger; 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 e990c4750..d1152e85f 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,23 +19,24 @@ package com.sk89q.worldedit.util.formatting.component; -import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.collect.Iterables; import static com.sk89q.worldedit.internal.command.CommandUtil.getSubCommands; import com.google.common.collect.ImmutableList; -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 java.util.List; -import javax.annotation.Nullable; import org.enginehub.piston.Command; import org.enginehub.piston.CommandParameters; import org.enginehub.piston.NoInputCommandParameters; import org.enginehub.piston.config.ColorConfig; import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.part.CommandPart; + +import static com.google.common.base.Preconditions.checkNotNull; +import javax.annotation.Nullable; import org.enginehub.piston.util.HelpGenerator; /** 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 2ead3102f..6020b3b1b 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,8 +19,9 @@ package com.sk89q.worldedit.util.paste; -import com.boydti.fawe.util.IncendoPaster; import com.sk89q.worldedit.command.util.AsyncCommandBuilder; + +import com.boydti.fawe.util.IncendoPaster; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.util.task.Supervisor; 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 5e01dee84..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/Pastebin.java +++ /dev/null @@ -1,92 +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.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 Callable paste(String content) { - if (mungingLinks) { - content = content.replaceAll("http://", "http_//"); - } - - return 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/world/AbstractWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java index 6a240e91a..019e57971 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,13 +33,13 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; 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.block.BlockType; + +import java.nio.file.Path; +import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.weather.WeatherTypes; import javax.annotation.Nullable; -import java.nio.file.Path; import java.util.PriorityQueue; /** 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 1f0fd8850..a1d6e28d4 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,16 +20,18 @@ package com.sk89q.worldedit.world.block; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.blocks.TileEntityBlock; import com.sk89q.worldedit.extent.OutputExtent; import com.sk89q.worldedit.function.pattern.FawePattern; + +import java.util.Locale; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.PropertyKey; import com.sk89q.worldedit.world.registry.BlockMaterial; import javax.annotation.Nullable; -import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; 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 60ab33cfe..5517a1b06 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,9 +19,8 @@ package com.sk89q.worldedit.world.block; -import static com.google.common.base.Preconditions.checkArgument; - import com.sk89q.worldedit.WorldEdit; +import com.google.common.collect.Iterables; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extent.Extent; @@ -35,6 +34,7 @@ import com.sk89q.worldedit.registry.state.AbstractProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.PropertyKey; import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.LegacyMapper; @@ -43,6 +43,8 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkArgument; import java.util.stream.IntStream; import javax.annotation.Nullable; @@ -102,6 +104,14 @@ public class BlockType implements FawePattern, Keyed { } } + private BlockState computeDefaultState() { + BlockState defaultState = Iterables.getFirst(getBlockStatesMap().values(), null); + if (values != null) { + defaultState = values.apply(defaultState); + } + return defaultState; + } + @Deprecated public BlockState withPropertyId(int propertyId) { if (settings.stateOrdinals == null) return settings.defaultState; 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 480753779..afaff434a 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 @@ -50,6 +50,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import java.util.Optional; /** * Stores a list of common Block String IDs. 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 3dd9bf599..6989f7731 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 @@ -23,9 +23,8 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; -import java.util.OptionalInt; - import javax.annotation.Nullable; +import java.util.OptionalInt; import java.util.Collection; import java.util.Collections; import java.util.Map; 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 32bf52e73..a032921e5 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 @@ -50,12 +50,15 @@ import java.io.IOException; import java.net.URL; import java.nio.charset.Charset; import java.util.Map; +import java.util.HashMap; public final class LegacyMapper { private static final Logger log = LoggerFactory.getLogger(LegacyMapper.class); private static LegacyMapper INSTANCE = new LegacyMapper(); + private Map blockEntries = new HashMap<>(); + private final Int2ObjectArrayMap blockStateToLegacyId4Data = new Int2ObjectArrayMap<>(); private final Int2ObjectArrayMap extraId4DataToStateId = new Int2ObjectArrayMap<>(); private final int[] blockArr = new int[4096]; @@ -95,20 +98,31 @@ public final class LegacyMapper { parserContext.setTryLegacy(false); // This is legacy. Don't match itself. for (Map.Entry blockEntry : dataFile.blocks.entrySet()) { + String id = blockEntry.getKey(); + Integer combinedId = getCombinedId(blockEntry.getKey()); + final String value = blockEntry.getValue(); + blockEntries.put(id, value); + BlockState blockState; try { - BlockState blockState = BlockState.get(null, blockEntry.getValue()); + blockState = BlockState.get(null, blockEntry.getValue()); BlockType type = blockState.getBlockType(); if (type.hasProperty(PropertyKey.WATERLOGGED)) { blockState = blockState.with(PropertyKey.WATERLOGGED, false); } - Integer combinedId = getCombinedId(blockEntry.getKey()); - blockArr[combinedId] = blockState.getInternalId(); - - blockStateToLegacyId4Data.put(blockState.getInternalId(), (Integer) combinedId); - blockStateToLegacyId4Data.putIfAbsent(blockState.getInternalBlockTypeId(), combinedId); } catch (InputParseException e) { - log.warn("Unknown block: " + blockEntry.getValue()); + if (fixer != null) { + String newEntry = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, value, 1631); + try { + blockState = WorldEdit.getInstance().getBlockFactory().parseFromInput(newEntry, parserContext).toImmutableState(); + } catch (InputParseException ignored) { + log.warn("Unknown block: " + value); + continue; + } + } } + blockArr[combinedId] = blockState.getInternalId(); + blockStateToLegacyId4Data.put(blockState.getInternalId(), (Integer) combinedId); + blockStateToLegacyId4Data.putIfAbsent(blockState.getInternalBlockTypeId(), combinedId); } for (int id = 0; id < 256; id++) { int combinedId = id << 4; @@ -123,8 +137,6 @@ public final class LegacyMapper { for (Map.Entry itemEntry : dataFile.items.entrySet()) { try { itemMap.put(getCombinedId(itemEntry.getKey()), ItemTypes.get(itemEntry.getValue())); - } catch (Exception e) { - log.warn("Unknown item: " + itemEntry.getValue()); } } } 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-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 d13663427..77424ddc0 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 @@ -22,6 +22,7 @@ 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; @@ -31,7 +32,6 @@ import java.util.Calendar; import java.util.Collections; import java.util.List; import java.util.Locale; -import javax.annotation.Nullable; /** * A repository contains zero or more snapshots. 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 6e7b1766f..ec03ba6b1 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 @@ -123,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 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 0c2fb8843..749451370 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,6 +25,8 @@ import com.sk89q.worldedit.world.block.BlockType; import java.util.HashSet; import java.util.Set; import org.junit.jupiter.api.BeforeEach; + +import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; 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..20eec91ae --- /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); + } + + 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(); + } + + @AfterEach + void tearDown() { + WorldEdit.getInstance().getPlatformManager().unregister(mockPlat); + } + + 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 de9cce3cc..73e747e6d 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,17 +19,13 @@ 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 org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; + +import java.time.Duration; 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 static java.lang.Math.atan2; import static java.lang.Math.sin; @@ -40,20 +36,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class ExpressionTest { +class ExpressionTest extends BaseExpressionTest { 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); @@ -77,73 +63,78 @@ 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() { - 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,53 +173,12 @@ 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")); } - 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, EvaluationException { - 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)); + } +} 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 9330bf513..a68069f85 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 @@ -20,11 +20,11 @@ package com.sk89q.worldedit.util; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.world.World; import org.junit.jupiter.api.Test; +import static org.mockito.Mockito.mock; /** * Tests {@link Location}. 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/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java index 3e85c6fee..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,13 +19,14 @@ package com.sk89q.worldedit.util.eventbus; -import static java.util.Arrays.asList; -import static java.util.Collections.singletonList; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; -import org.junit.jupiter.api.Test; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.assertEquals; public class EventBusTest { 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 diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts new file mode 100644 index 000000000..fa38ce619 --- /dev/null +++ b/worldedit-fabric/build.gradle.kts @@ -0,0 +1,103 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import net.fabricmc.loom.task.RemapJarTask + +applyPlatformAndCoreConfiguration() +applyShadowConfiguration() + +apply(plugin = "fabric-loom") + +val minecraftVersion = "1.14.4" +val yarnMappings = "1.14.4+build.12" +val loaderVersion = "0.6.2+build.166" + +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") + + 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) + } + + // 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") +} + +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"]) + + 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") + 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")) + } +} + +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) + input.set(shadowJar.archiveFile) + archiveFileName.set(shadowJar.archiveFileName.get().replace(Regex("-dev\\.jar$"), ".jar")) + addNestedDependencies.set(true) +} + +tasks.named("assemble").configure { + dependsOn("remapShadowJar") +} 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..462975acb --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/CommandWrapper.java @@ -0,0 +1,129 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * 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(" ") + && !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..692d350e1 --- /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.getName().asFormattedString(); + } + } + +} \ 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..87a72c9f6 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockCategoryRegistry.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.fabric; + +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()); + } +} 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..593e95817 --- /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.getName().asFormattedString(); + } 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/FabricWatchdog.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricConfiguration.java similarity index 59% rename from worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java rename to worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricConfiguration.java index b0f25c685..ab00d6f89 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricConfiguration.java @@ -19,21 +19,27 @@ 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; +import com.sk89q.worldedit.util.PropertiesConfiguration; -class FabricWatchdog implements Watchdog { +import java.io.File; - private final MinecraftDedicatedServer server; +public class FabricConfiguration extends PropertiesConfiguration { - FabricWatchdog(MinecraftDedicatedServer server) { - this.server = server; + public boolean creativeEnable = false; + public boolean cheatMode = false; + + public FabricConfiguration(FabricWorldEdit mod) { + super(new File(mod.getWorkingDir(), "worldedit.properties")); } @Override - public void tick() { - ((MixinMinecraftServer) (Object) server).timeReference = SystemUtil.getMeasuringTimeMs(); + 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..f307b789c --- /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.text.LiteralText; +import net.minecraft.text.Text; +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 LiteralText(s); + } else { + try { + object = JsonHelper.deserialize(DataConverterSignText.a, s, Text.class, true); + if (object == null) { + object = new LiteralText(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Text.Serializer.fromJson(s); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Text.Serializer.fromLenientJson(s); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = new LiteralText(s); + } + } + } else { + object = new LiteralText(""); + } + + nbttaglist.set(i, new StringTag(Text.Serializer.toJson((Text) 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(Text.class, new JsonDeserializer() { + Text a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { + if (jsonelement.isJsonPrimitive()) { + return new LiteralText(jsonelement.getAsString()); + } else if (jsonelement.isJsonArray()) { + JsonArray jsonarray = jsonelement.getAsJsonArray(); + Text iTextComponent = null; + Iterator iterator = jsonarray.iterator(); + + while (iterator.hasNext()) { + JsonElement jsonelement1 = (JsonElement) iterator.next(); + Text 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 LiteralText(s1); + } else { + try { + object = JsonHelper.deserialize(DataConverterSignText.a, s1, Text.class, true); + if (object == null) { + object = new LiteralText(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Text.Serializer.fromJson(s1); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Text.Serializer.fromLenientJson(s1); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = new LiteralText(s1); + } + } + } else { + object = new LiteralText(""); + } + + nbttagcompound.putString(s, Text.Serializer.toJson((Text) 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..bcdc7a0c2 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemCategoryRegistry.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.fabric; + +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()); + } +} diff --git a/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/ItemRegistryTest.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemRegistry.java similarity index 56% rename from worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/ItemRegistryTest.java rename to worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemRegistry.java index d8e6a8f91..e3497234f 100644 --- a/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/ItemRegistryTest.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemRegistry.java @@ -17,23 +17,26 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit; +package com.sk89q.worldedit.fabric; import com.sk89q.worldedit.world.item.ItemType; -import org.bukkit.Material; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; +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; -public class ItemRegistryTest { +import javax.annotation.Nullable; - @Test - public void testItemRegistry() { - for (Material material : Material.values()) { - if (material.isItem() && !material.isLegacy()) { - ItemType.REGISTRY.register(material.getKey().toString(), new ItemType(material.getKey().toString())); - } +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()); } - Assertions.assertNotNull(ItemType.REGISTRY.get("minecraft:wooden_axe")); + 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 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/FabricPlayer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java new file mode 100644 index 000000000..60003a259 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java @@ -0,0 +1,281 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * 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.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; +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.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.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; + +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().asFormattedString(); + } + + @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 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 LiteralText(part)); + } + } + + @Override + public void printDebug(String msg) { + sendColorized(msg, Formatting.GRAY); + } + + @Override + public void print(String msg) { + sendColorized(msg, Formatting.LIGHT_PURPLE); + } + + @Override + public void printError(String msg) { + sendColorized(msg, Formatting.RED); + } + + @Override + public void print(Component component) { + this.player.sendMessage(Text.Serializer.fromJson(GsonComponentSerializer.INSTANCE.serialize(WorldEditText.format(component)))); + } + + private void sendColorized(String msg, Formatting formatting) { + for (String part : msg.split("\n")) { + LiteralText component = new LiteralText(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 boolean isAllowedToFly() { + return player.abilities.allowFlying; + } + + @Override + public void setFlying(boolean flying) { + if (player.abilities.flying != flying) { + player.abilities.flying = flying; + player.sendAbilitiesUpdate(); + } + } + + @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..886523df5 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java @@ -0,0 +1,618 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * 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.Locale; +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 String getId() { + return getWorld().getLevelProperties().getLevelName() + .replace(" ", "_").toLowerCase(Locale.ROOT) + + getWorld().dimension.getType().getSuffix(); + } + + @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); + 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 + } + } + } + } + + 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; + } + + @Override + public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException { + BlockPos pos = new BlockPos(position.getX(), position.getY(), position.getZ()); + net.minecraft.block.BlockState state = getWorld().getBlockState(pos); + getWorld().updateListeners(pos, FabricAdapter.adapt(previousType), state, 1 | 2); + getWorld().updateNeighbors(pos, state.getBlock()); + 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) { + 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(); + } + } + + @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/WorldEditFakePlayer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/WorldEditFakePlayer.java new file mode 100644 index 000000000..b1dad7904 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/WorldEditFakePlayer.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.fabric; + +import com.mojang.authlib.GameProfile; +import net.minecraft.entity.Entity; +import net.minecraft.entity.damage.DamageSource; +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 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]"); + + 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(Text component) { + } + + @Override + public void addChatMessage(Text 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/MixinMinecraftServer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java index de54985b8..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 @@ -19,21 +19,27 @@ package com.sk89q.worldedit.fabric.mixin; -import net.minecraft.server.MinecraftServer; +import com.sk89q.worldedit.extension.platform.Watchdog; import net.minecraft.server.ServerTask; -import net.minecraft.server.command.CommandOutput; +import net.minecraft.server.MinecraftServer; 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/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 000000000..dc269dcf7 Binary files /dev/null and b/worldedit-fabric/src/main/resources/assets/worldedit/icon.png differ diff --git a/worldedit-fabric/src/main/resources/defaults/worldedit.properties b/worldedit-fabric/src/main/resources/defaults/worldedit.properties new file mode 100644 index 000000000..d0296c15c --- /dev/null +++ b/worldedit-fabric/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-fabric/src/main/resources/fabric.mod.json b/worldedit-fabric/src/main/resources/fabric.mod.json new file mode 100644 index 000000000..705320db0 --- /dev/null +++ b/worldedit-fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,40 @@ +{ + "schemaVersion": 1, + "id": "worldedit", + "version": "${version}", + + "name": "WorldEdit", + "description": "WorldEdit is an easy-to-use in-game world editor for Minecraft, supporting both single- and multi-player.", + "authors": [ + "sk89q", + "wizjany", + "TomyLobo", + "kenzierocks", + "Me4502" + ], + "contact": { + "homepage": "https://enginehub.org/worldedit/", + "sources": "https://github.com/EngineHub/WorldEdit" + }, + + "license": "GPL3", + "icon": "assets/worldedit/icon.png", + + "environment": "*", + "entrypoints": { + "main": [ + "com.sk89q.worldedit.fabric.FabricWorldEdit" + ] + }, + + "depends": { + "fabricloader": ">=0.4.0", + "fabric-api-base": "*", + "fabric-events-lifecycle-v0": "*", + "fabric-events-interaction-v0": "*", + "fabric-networking-v0": "*" + }, + "mixins": [ + "worldedit.mixins.json" + ] +} 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-forge/build.gradle b/worldedit-forge/build.gradle deleted file mode 100644 index 8fe3fb9af..000000000 --- a/worldedit-forge/build.gradle +++ /dev/null @@ -1,111 +0,0 @@ -buildscript { - repositories { - mavenLocal() - mavenCentral() - maven { url = "https://files.minecraftforge.net/maven" } - jcenter() - } - - dependencies { - classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true - } -} - -apply plugin: 'net.minecraftforge.gradle' - -def minecraftVersion = "1.13.2" -def forgeVersion = "25.0.76" - -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: '20190311-1.13.2' - - 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 - } - } - - accessTransformer = file('worldedit_at.cfg') -} - -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("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", - "WorldEdit-Version": version, - "FMLAT": "worldedit_at.cfg") - } -} - -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")) - } -} - -afterEvaluate { - reobf { - shadowJar { - mappings = createMcpToSrg.output - } - } -} - -task deobfJar(type: Jar) { - from sourceSets.main.output - classifier = 'dev' -} - -artifacts { - archives deobfJar -} 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..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 @@ -19,27 +19,49 @@ 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.tree.LiteralCommandNode; -import com.sk89q.worldedit.util.command.CommandMapping; +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.command.CommandSource; -import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.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; +import static net.minecraft.command.Commands.argument; import static net.minecraft.command.Commands.literal; public final class CommandWrapper { private CommandWrapper() { } - public static void register(CommandDispatcher dispatcher, CommandMapping command) { - for (String alias : command.getAllAliases()) { - LiteralArgumentBuilder base = literal(alias) - .executes(FAKE_COMMAND); - if (command.getDescription().getPermissions().size() > 0) { + 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) + .then(argument("args", StringArgumentType.greedyString()) + .suggests(CommandWrapper::suggest) + .executes(FAKE_COMMAND)); + if (command.getCondition() != org.enginehub.piston.Command.Condition.TRUE) { base.requires(requirementsFor(command)); } dispatcher.register(base); @@ -47,22 +69,53 @@ 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; }; - 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() - .allMatch(perm -> permsProvider.hasPermission( - (EntityPlayerMP) ctx.getEntity(), perm - )); + final Entity entity = ctx.getEntity(); + 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); }; } + 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(" ") + && !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-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java index 164ac65cf..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 @@ -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; @@ -39,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; @@ -91,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; @@ -148,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(); } @@ -157,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(() -> { @@ -177,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) { @@ -206,15 +205,27 @@ 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()); } - 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()); } @@ -224,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/ForgeBlockCategoryRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.java new file mode 100644 index 000000000..0290dbdd6 --- /dev/null +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.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.forge; + +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()); + } +} 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 290642abb..90b8dfddc 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,6 +20,7 @@ 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; @@ -29,13 +30,15 @@ import net.minecraft.block.properties.IProperty; import net.minecraft.util.ResourceLocation; import net.minecraft.state.IProperty; +import javax.annotation.Nullable; +import net.minecraftforge.fml.loading.FMLLoader; +import java.util.OptionalInt; + import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; -import javax.annotation.Nullable; - public class ForgeBlockRegistry extends BundledBlockRegistry { private Map materialMap = new HashMap<>(); @@ -44,7 +47,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); @@ -74,4 +77,9 @@ public class ForgeBlockRegistry extends BundledBlockRegistry { return map; } + @Override + public OptionalInt getInternalBlockStateId(BlockState 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 new file mode 100644 index 000000000..23e1eb9a4 --- /dev/null +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.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.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.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.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.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.StringTextComponent; +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) { + CompoundNBT tag = NBTConverter.toNative(originalChunk); + CompoundNBT fixed = convert(LegacyType.CHUNK, tag, srcVer); + return NBTConverter.fromNative(fixed); + } + + private CompoundTag fixBlockEntity(CompoundTag origTileEnt, int 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) { + CompoundNBT tag = NBTConverter.toNative(origEnt); + CompoundNBT fixed = convert(LegacyType.ENTITY, tag, srcVer); + return NBTConverter.fromNative(fixed); + } + + private String fixBlockState(String blockState, int srcVer) { + 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(CompoundNBT tagCompound) { + StringBuilder sb = new StringBuilder(); + sb.append(tagCompound.getString("Name")); + if (tagCompound.contains("Properties", 10)) { + sb.append('['); + 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 CompoundNBT stateToNBT(String blockState) { + int propIdx = blockState.indexOf('['); + CompoundNBT tag = new CompoundNBT(); + if (propIdx < 0) { + tag.putString("Name", blockState); + } else { + tag.putString("Name", blockState.substring(0, propIdx)); + CompoundNBT propTag = new CompoundNBT(); + 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 StringNBT(key)), srcVer, DATA_VERSION) + .asString().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(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; + } + } + + ForgeDataFixer(int dataVersion) { + super(dataVersion); + DATA_VERSION = dataVersion; + INSTANCE = this; + registerConverters(); + registerInspectors(); + this.fixer = new WrappedDataFixer(DataFixesManager.getDataFixer()); + } + + @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) { + CompoundNBT cmp = (CompoundNBT) 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 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) { + 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 CompoundNBT convert(LegacyType type, CompoundNBT cmp) { + return convert(type.getDFUType(), cmp); + } + + public static CompoundNBT convert(LegacyType type, CompoundNBT cmp, int sourceVer) { + return convert(type.getDFUType(), cmp, sourceVer); + } + + public static CompoundNBT convert(LegacyType type, CompoundNBT cmp, int sourceVer, int targetVer) { + return convert(type.getDFUType(), cmp, sourceVer, targetVer); + } + + 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 CompoundNBT convert(TypeReference type, CompoundNBT cmp, int sourceVer) { + return convert(type, cmp, sourceVer, DATA_VERSION); + } + + public static CompoundNBT convert(TypeReference type, CompoundNBT cmp, int sourceVer, int targetVer) { + if (sourceVer >= targetVer) { + return cmp; + } + return (CompoundNBT) INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, cmp), sourceVer, targetVer).getValue(); + } + + + public interface DataInspector { + CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer); + } + + public interface DataConverter { + + int getDataVersion(); + + CompoundNBT convert(CompoundNBT 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, CompoundNBT cmp, String key, int sourceVer, int targetVer) { + cmp.put(key, convert(type, cmp.getCompound(key), sourceVer, 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(CompoundNBT nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.contains(key, 9)) { + 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)); + } + } + + } + + private static class DataConverterEquipment implements DataConverter { + + DataConverterEquipment() {} + + @Override + public int getDataVersion() { + return 100; + } + + @Override + public CompoundNBT convert(CompoundNBT cmp) { + ListNBT nbttaglist = cmp.getList("Equipment", 10); + ListNBT nbttaglist1; + + if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { + nbttaglist1 = new ListNBT(); + nbttaglist1.add(nbttaglist.get(0)); + nbttaglist1.add(new CompoundNBT()); + cmp.put("HandItems", nbttaglist1); + } + + if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { + nbttaglist1 = new ListNBT(); + 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); + ListNBT nbttaglist2; + + if (!cmp.contains("HandDropChances", 10)) { + 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 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); + } + + 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 CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { + if (!cmp.contains("tag", 10)) { + return cmp; + } else { + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + CompoundNBT 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 CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("EntityTag", 10)) { + CompoundNBT 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 CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { + if (this.key.equals(new ResourceLocation(cmp.getString("id")))) { + cmp = this.inspectChecked(cmp, sourceVer, targetVer); + } + + return cmp; + } + + abstract CompoundNBT inspectChecked(CompoundNBT 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; + } + + CompoundNBT inspectChecked(CompoundNBT 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; + } + + CompoundNBT inspectChecked(CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT cmp) { + if ("minecraft:banner".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + CompoundNBT nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + + if (nbttagcompound2.contains("Base", 99)) { + cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); + if (nbttagcompound1.contains("display", 10)) { + CompoundNBT nbttagcompound3 = nbttagcompound1.getCompound("display"); + + if (nbttagcompound3.contains("Lore", 9)) { + ListNBT 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 CompoundNBT convert(CompoundNBT cmp) { + if ("minecraft:potion".equals(cmp.getString("id"))) { + CompoundNBT 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 CompoundNBT convert(CompoundNBT cmp) { + if ("minecraft:spawn_egg".equals(cmp.getString("id"))) { + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); + CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT cmp) { + if (!"MobSpawner".equals(cmp.getString("id"))) { + return cmp; + } else { + if (cmp.contains("EntityId", 8)) { + String s = cmp.getString("EntityId"); + CompoundNBT nbttagcompound1 = cmp.getCompound("SpawnData"); + + nbttagcompound1.putString("id", s.isEmpty() ? "Pig" : s); + cmp.put("SpawnData", nbttagcompound1); + cmp.remove("EntityId"); + } + + if (cmp.contains("SpawnPotentials", 9)) { + ListNBT nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int i = 0; i < nbttaglist.size(); ++i) { + CompoundNBT nbttagcompound2 = nbttaglist.getCompound(i); + + if (nbttagcompound2.contains("Type", 8)) { + CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT cmp) { + if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("SaddleItem", 10) && cmp.getBoolean("Saddle")) { + CompoundNBT nbttagcompound1 = new CompoundNBT(); + + 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 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)) { + Direction enumdirection; + + if (cmp.contains("Direction", 99)) { + 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()); + cmp.remove("Direction"); + if (flag1 && cmp.contains("ItemRotation", 99)) { + cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); + } + } else { + enumdirection = Direction.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 CompoundNBT convert(CompoundNBT cmp) { + ListNBT 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 CompoundNBT convert(CompoundNBT cmp) { + while (cmp.contains("Riding", 10)) { + CompoundNBT nbttagcompound1 = this.b(cmp); + + this.convert(cmp, nbttagcompound1); + cmp = nbttagcompound1; + } + + return cmp; + } + + protected void convert(CompoundNBT nbttagcompound, CompoundNBT nbttagcompound1) { + ListNBT nbttaglist = new ListNBT(); + + nbttaglist.add(nbttagcompound); + nbttagcompound1.put("Passengers", nbttaglist); + } + + protected CompoundNBT b(CompoundNBT nbttagcompound) { + CompoundNBT nbttagcompound1 = nbttagcompound.getCompound("Riding"); + + nbttagcompound.remove("Riding"); + return nbttagcompound1; + } + } + + private static class DataConverterBook implements DataConverter { + + DataConverterBook() {} + + public int getDataVersion() { + return 165; + } + + public CompoundNBT convert(CompoundNBT cmp) { + if ("minecraft:written_book".equals(cmp.getString("id"))) { + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("pages", 9)) { + ListNBT 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 StringTextComponent(s); + } else { + try { + object = JSONUtils.fromJson(DataConverterSignText.a, s, ITextComponent.class, true); + if (object == null) { + object = new StringTextComponent(""); + } + } 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 StringTextComponent(s); + } + } + } else { + object = new StringTextComponent(""); + } + + nbttaglist.set(i, new StringNBT(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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT cmp) { + cmp.putString("useVbo", "true"); + return cmp; + } + } + + private static class DataConverterGuardian implements DataConverter { + + DataConverterGuardian() {} + + public int getDataVersion() { + return 700; + } + + public CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 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)) { + CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT cmp) { + if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT 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 CompoundNBT convert(CompoundNBT cmp) { + boolean flag = true; + + try { + CompoundNBT nbttagcompound1 = cmp.getCompound("Level"); + int i = nbttagcompound1.getInt("xPos"); + int j = nbttagcompound1.getInt("zPos"); + ListNBT nbttaglist = nbttagcompound1.getList("TileEntities", 10); + ListNBT nbttaglist1 = nbttagcompound1.getList("Sections", 10); + + for (int k = 0; k < nbttaglist1.size(); ++k) { + CompoundNBT 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; + CompoundNBT nbttagcompound3 = new CompoundNBT(); + + 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 CompoundNBT convert(CompoundNBT 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(ITextComponent.class, new JsonDeserializer() { + ITextComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { + if (jsonelement.isJsonPrimitive()) { + return new StringTextComponent(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 CompoundNBT convert(CompoundNBT 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(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 StringTextComponent(s1); + } else { + try { + object = JSONUtils.fromJson(DataConverterSignText.a, s1, ITextComponent.class, true); + if (object == null) { + object = new StringTextComponent(""); + } + } 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 StringTextComponent(s1); + } + } + } else { + object = new StringTextComponent(""); + } + + nbttagcompound.putString(s, ITextComponent.Serializer.toJson((ITextComponent) object)); + } + } + + private static class DataInspectorPlayerVehicle implements DataInspector { + @Override + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { + if (cmp.contains("RootVehicle", 10)) { + CompoundNBT 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 CompoundNBT inspect(CompoundNBT 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 CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { + ListNBT nbttaglist; + int j; + CompoundNBT nbttagcompound1; + + if (cmp.contains("entities", 9)) { + nbttaglist = cmp.getList("entities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttagcompound1 = (CompoundNBT) 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 = (CompoundNBT) 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 CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { + if (cmp.contains("Level", 10)) { + 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, (CompoundNBT) 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, (CompoundNBT) nbttaglist.get(j), sourceVer, targetVer)); + } + } + } + + return cmp; + } + } + + private static class DataInspectorEntityPassengers implements DataInspector { + @Override + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { + if (cmp.contains("Passengers", 9)) { + 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)); + } + } + + return cmp; + } + } + + private static class DataInspectorPlayer implements DataInspector { + @Override + public CompoundNBT inspect(CompoundNBT 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 CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { + if (entityVillager.equals(new ResourceLocation(cmp.getString("id"))) && cmp.contains("Offers", 10)) { + CompoundNBT nbttagcompound1 = cmp.getCompound("Offers"); + + if (nbttagcompound1.contains("Recipes", 9)) { + ListNBT nbttaglist = nbttagcompound1.getList("Recipes", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + CompoundNBT 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 CompoundNBT inspect(CompoundNBT 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 CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { + if (tileEntityMobSpawner.equals(new ResourceLocation(cmp.getString("id")))) { + if (cmp.contains("SpawnPotentials", 9)) { + ListNBT nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + CompoundNBT 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 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); + cmp.putString("id", "MinecartCommandBlock"); + } + + return cmp; + } + } +} 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-core/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java similarity index 52% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java rename to worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java index 76d875851..8dd4bbb99 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java @@ -17,28 +17,24 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.command.factory; +package com.sk89q.worldedit.forge; -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.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; -public final class TreeGeneratorFactory implements Contextual { - private final TreeGenerator.TreeType type; - - public TreeGeneratorFactory(TreeGenerator.TreeType type) { - this.type = type; - } +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +public class ForgeItemCategoryRegistry implements ItemCategoryRegistry { @Override - public ForestGenerator createFromContext(EditContext input) { - return new ForestGenerator((EditSession) input.getDestination(), type); - } - - @Override - public String toString() { - return "tree of type " + type; + 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()); } } 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 4af39eb46..3221c7d71 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 @@ -28,12 +28,24 @@ import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.BundledItemRegistry; import javax.annotation.Nullable; +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; 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/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 bee73aa69..67858919d 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,31 +19,39 @@ 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.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.dedicated.DedicatedServer; import net.minecraft.server.management.PlayerList; import net.minecraft.util.ResourceLocation; -import net.minecraft.world.WorldServer; import net.minecraftforge.fml.server.ServerLifecycleHooks; +import net.minecraft.util.SharedConstants; +import net.minecraft.world.server.ServerWorld; import javax.annotation.Nullable; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandManager; import java.util.ArrayList; import java.util.Collection; import java.util.EnumMap; +import java.util.Collections; 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 { @@ -80,21 +88,33 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { getConfiguration().load(); } + @Override + public int getDataVersion() { + return SharedConstants.getVersion().getWorldVersion(); + } + + @Override + public DataFixer getDataFixer() { + return dataFixer; + } + @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 (WorldServer world : worlds) { @Nullable public ForgeWatchdog getWatchdog() { return watchdog; } + @Override + public List getWorlds() { + Iterable worlds = server.getWorlds(); + List ret = new ArrayList<>(); + for (ServerWorld world : worlds) { + @Override public List getWorlds() { Iterable worlds = server.getWorlds(); @@ -111,7 +131,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; } } @@ -122,7 +142,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); } @@ -133,16 +153,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.isEmpty()) { + perms.forEach(ForgeWorldEdit.inst.getPermissionsProvider()::registerPermission); } } } @@ -189,7 +210,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 4e466312c..6d6877c96 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,8 @@ 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; @@ -31,30 +33,42 @@ 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.world.block.BaseBlock; +import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockStateHolder; - -import net.minecraft.entity.player.EntityPlayerMP; +import com.sk89q.worldedit.world.block.BlockTypes; import net.minecraft.item.ItemStack; + +import io.netty.buffer.Unpooled; +import net.minecraft.block.Block; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.network.PacketBuffer; -import net.minecraft.network.play.server.SPacketCustomPayload; -import net.minecraft.util.EnumHand; +import net.minecraft.network.play.server.SChangeBlockPacket; +import net.minecraft.network.play.server.SCustomPayloadPlayPacket; import net.minecraft.util.ResourceLocation; +import net.minecraft.network.play.server.SUpdateTileEntityPacket; +import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; +import java.io.IOException; + import java.util.UUID; import javax.annotation.Nullable; -import io.netty.buffer.Unpooled; - public class ForgePlayer extends AbstractPlayerActor { - private final EntityPlayerMP player; + // 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 ForgePlayer(EntityPlayerMP player) { + protected ForgePlayer(ServerPlayerEntity player) { this.player = player; ThreadSafeCache.getInstance().getOnlineIds().add(getUniqueId()); } @@ -66,7 +80,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); } @@ -97,7 +111,7 @@ public class ForgePlayer extends AbstractPlayerActor { } @Override - public com.sk89q.worldedit.world.World getWorld() { + public World getWorld() { return ForgeWorldEdit.inst.getWorld(this.player.world); } @@ -114,14 +128,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.MOD_ID, 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)); } } @@ -140,9 +154,14 @@ public class ForgePlayer extends AbstractPlayerActor { sendColorized(msg, TextFormatting.RED); } + @Override + public void print(Component component) { + this.player.sendMessage(ITextComponent.Serializer.fromJson(GsonComponentSerializer.INSTANCE.serialize(WorldEditText.format(component)))); + } + 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); } @@ -174,20 +193,50 @@ public class ForgePlayer extends AbstractPlayerActor { return null; } + @Override + public boolean isAllowedToFly() { + return player.abilities.allowFlying; + } + + @Override + public void setFlying(boolean flying) { + if (player.abilities.isFlying != flying) { + player.abilities.isFlying = flying; + player.sendPlayerAbilities(); + } + } + @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 SChangeBlockPacket packetOut = new SChangeBlockPacket(((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 SChangeBlockPacket packetOut = new SChangeBlockPacket(); + 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 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/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 43a9399b9..6f484b06b 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,7 +19,10 @@ 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; @@ -30,9 +33,11 @@ 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; @@ -45,29 +50,36 @@ 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.BlockLeaves; -import net.minecraft.block.state.IBlockState; 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.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.block.LeavesBlock; +import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.ItemStack; +import net.minecraft.inventory.IClearable; import net.minecraft.item.ItemUseContext; -import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumActionResult; -import net.minecraft.util.ResourceLocation; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Hand; import net.minecraft.world.World; -import net.minecraft.world.WorldServer; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.ChunkPos; import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.AbstractChunkProvider; import net.minecraft.world.gen.feature.BigBrownMushroomFeature; +import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.chunk.IChunk; +import net.minecraft.world.chunk.listener.IChunkStatusListener; import net.minecraft.world.gen.feature.BigRedMushroomFeature; +import net.minecraft.world.gen.feature.BigMushroomFeatureConfig; 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; @@ -81,12 +93,25 @@ import net.minecraft.world.gen.feature.TreeFeature; import net.minecraft.world.storage.WorldInfo; import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; -import java.util.concurrent.ThreadLocalRandom; +import net.minecraft.world.server.ServerChunkProvider; +import net.minecraft.world.server.ServerWorld; +import net.minecraft.world.storage.SaveHandler; +import net.minecraftforge.common.DimensionManager; import javax.annotation.Nullable; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Random; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; /** * An adapter to Minecraft worlds for WorldEdit. @@ -96,9 +121,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; @@ -147,6 +172,20 @@ 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(); + 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); @@ -160,9 +199,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); - IBlockState newState = ForgeAdapter.adapt(block.toImmutableState()); - IBlockState successState = chunk.setBlockState(pos, newState, false); + net.minecraft.block.BlockState old = chunk.getBlockState(pos); + OptionalInt stateId = BlockStateIdAccess.getBlockStateId(block.toImmutableState()); + 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 @@ -170,15 +210,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); } @@ -202,12 +243,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; @@ -224,36 +261,45 @@ 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); + chunk.setModified(true); + return true; } + private static LoadingCache fakePlayers + = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(WorldEditFakePlayer::new)); + @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)); + ServerWorld world = (ServerWorld) getWorld(); + final WorldEditFakePlayer fakePlayer; + try { + fakePlayer = fakePlayers.get(world); + } catch (ExecutionException ignored) { + return false; } - World world = getWorld(); - ItemUseContext itemUseContext = new ItemUseContext( - new WorldEditFakePlayer((WorldServer) world), - stack, - ForgeAdapter.toBlockPos(position), - ForgeAdapter.adapt(face), - 0f, - 0f, - 0f - ); - EnumActionResult used = stack.onItemUse(itemUseContext); - return used != EnumActionResult.FAIL; + 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 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, fakePlayer, Hand.MAIN_HAND, rayTraceResult)) { + used = ActionResultType.SUCCESS; + } else { + used = stack.getItem().onItemRightClick(world, fakePlayer, Hand.MAIN_HAND).getType(); + } + } + return used == ActionResultType.SUCCESS; } @Override @@ -265,94 +311,100 @@ 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) { - // 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. + AbstractChunkProvider provider = getWorld().getChunkProvider(); + if (!(provider instanceof ServerChunkProvider)) { + 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(); + SaveHandler saveHandler = new SaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer()); + 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()); + } + + 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); + } finally { + saveFolder.delete(); + } + + return true; } @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 @@ -369,7 +421,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); } } @@ -432,20 +484,14 @@ 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() - ); - - return ForgeAdapter.adapt(mcState); + public int getMaxY() { + return getWorld().getMaxHeight() - 1; } @Override public BaseBlock getFullBlock(BlockVector3 position) { BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - TileEntity tile = getWorld().getTileEntity(pos); + TileEntity tile = getWorld().getChunk(pos).getTileEntity(pos); if (tile != null) { return getBlock(position).toBaseBlock(NBTConverter.fromNative(TileEntityUtils.copyNbtData(tile))); @@ -454,6 +500,20 @@ public class ForgeWorld extends AbstractWorld { } } + @Override + public BlockState getBlock(BlockVector3 position) { + 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) { + return matchingBlock; + } + + return ForgeAdapter.adapt(mcState); + } + @Override public int hashCode() { return getWorld().hashCode(); @@ -477,33 +537,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.byKey(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); } @@ -512,7 +573,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; @@ -523,10 +584,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 start(ChunkPos chunkPos) { + } + + @Override + public void statusChanged(ChunkPos chunkPos, @Nullable ChunkStatus chunkStatus) { + } + + @Override + public void stop() { + } + } } 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 44e4974f6..1dfe19e06 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; @@ -34,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; @@ -41,14 +39,13 @@ 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.entity.player.ServerPlayerEntity; 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.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; @@ -61,12 +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; @@ -77,6 +72,10 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; +import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer; /** * The Forge implementation of WorldEdit. @@ -105,7 +104,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 +129,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 +139,6 @@ public class ForgeWorldEdit { // } else { this.provider = new ForgePermissionsProvider.VanillaPermissionsProvider(platform); // } - - setupRegistries(); - - config = new ForgeConfiguration(this); - config.load(); } private void setupRegistries() { @@ -205,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.getInstance().getPlatformManager().unregister(platform); @@ -212,6 +195,11 @@ public class ForgeWorldEdit { @SubscribeEvent public void serverStarted(FMLServerStartedEvent event) { + setupPlatform(); + setupRegistries(); + + config = new ForgeConfiguration(this); + config.load(); WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); } @@ -226,10 +214,10 @@ 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; } - + boolean isLeftDeny = event instanceof PlayerInteractEvent.LeftClickBlock && ((PlayerInteractEvent.LeftClickBlock) event) .getUseItem() == Event.Result.DENY; @@ -237,19 +225,16 @@ 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() == Hand.OFF_HAND) { return; } WorldEdit we = WorldEdit.getInstance(); - ForgePlayer player = adaptPlayer((EntityPlayerMP) 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) { - 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()); @@ -280,10 +265,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; } @@ -312,7 +297,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 06c59eb7f..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,9 +22,10 @@ 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; -import net.minecraftforge.fml.common.gameevent.InputEvent.KeyInputEvent; import org.lwjgl.glfw.GLFW; public class KeyHandler { @@ -37,11 +38,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)); + 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..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 @@ -19,10 +19,10 @@ 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.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,12 +56,12 @@ public class ThreadSafeCache { if (now - lastRefresh > REFRESH_DELAY) { 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 35d6c8381..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 @@ -20,17 +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.server.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 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/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..4866f4394 --- /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 541577e1f..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 @@ -20,15 +20,10 @@ 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; -import net.minecraft.network.ThreadQuickExitException; -import net.minecraft.network.play.server.SPacketCustomPayload; -import net.minecraft.util.ResourceLocation; +import net.minecraft.entity.player.ServerPlayerEntity; 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; @@ -40,21 +35,17 @@ 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); - HANDLER.addListener(WECUIPacketHandler::callProcessPacket); } - public static void onPacketData(ServerCustomPayloadEvent event) { - EntityPlayerMP player = event.getSource().get().getSender(); + public static void onPacketData(ClientCustomPayloadEvent event) { + ServerPlayerEntity player = event.getSource().get().getSender(); LocalSession session = ForgeWorldEdit.inst.getSession(player); if (session.hasCUISupport()) { @@ -62,17 +53,9 @@ public final class WECUIPacketHandler { } String text = event.getPayload().toString(UTF_8_CHARSET); - session.handleCUIInitializationMessage(text); - session.describeCUI(adaptPlayer(player)); - } - - public static void callProcessPacket(ClientCustomPayloadEvent event) { - try { - new SPacketCustomPayload( - new ResourceLocation(ForgeWorldEdit.MOD_ID, ForgeWorldEdit.CUI_PLUGIN_CHANNEL), - event.getPayload() - ).processPacket(Minecraft.getInstance().player.connection); - } catch (ThreadQuickExitException ignored) { - } + final ForgePlayer actor = adaptPlayer(player); + session.handleCUIInitializationMessage(text, actor); + session.describeCUI(actor); } + } \ No newline at end of file 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; -// }); } } 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-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-logo.png b/worldedit-logo.png new file mode 100644 index 000000000..e0b515743 Binary files /dev/null and b/worldedit-logo.png differ diff --git a/worldedit-sponge/build.gradle b/worldedit-sponge/build.gradle deleted file mode 100644 index bd21cd568..000000000 --- a/worldedit-sponge/build.gradle +++ /dev/null @@ -1,74 +0,0 @@ -buildscript { - repositories { - mavenCentral() - maven { url = "http://files.minecraftforge.net/maven" } - maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" } - jcenter() - } -} - -plugins { - id 'org.spongepowered.plugin' version '0.9.0' -} - -repositories { - maven { url "https://repo.codemc.org/repository/maven-public" } -} - -dependencies { - compile project(':worldedit-core') - 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' -} - -sourceCompatibility = JavaVersion.VERSION_1_8 -targetCompatibility = JavaVersion.VERSION_1_8 - -jar.archiveName="fawe-sponge-${project.parent.version}.jar" -jar.destinationDir = file '../mvn/com/boydti/fawe-sponge/' + project.parent.version -task createPom << { - pom { - project { - groupId 'com.boydti' - artifactId 'fawe-sponge' - version project.parent.version - } - } - .getEffectivePom() - .setDependencies(new ArrayList<>()) - .writeTo("../mvn/com/boydti/fawe-sponge/${project.parent.version}/fawe-sponge-${project.parent.version}.pom") - pom { - project { - groupId 'com.boydti' - artifactId 'fawe-sponge' - version 'latest' - } - } - .getEffectivePom() - .setDependencies(new ArrayList<>()) - .writeTo("../mvn/com/boydti/fawe-sponge/latest/fawe-sponge-latest.pom") -} -task copyFiles { - doLast { - copy { - from "../mvn/com/boydti/fawe-sponge/${project.parent.version}/" - into '../mvn/com/boydti/fawe-sponge/latest/' - include('*.jar') - rename ("fawe-sponge-${project.parent.version}.jar", 'fawe-sponge-latest.jar') - } - } -} - -shadowJar { - dependencies { - include(dependency(':worldedit-core')) - include(dependency('org.bstats:bstats-sponge:1.4')) - } - archiveName = "${parent.name}-${project.name.replaceAll("worldedit-", "")}-${parent.version}.jar" - destinationDir = file '../target' -} - -build.dependsOn(shadowJar) -build.finalizedBy(copyFiles) -copyFiles.dependsOn(createPom) 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 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); } } } 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..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 @@ -19,50 +19,52 @@ 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; + +import static com.sk89q.worldedit.sponge.SpongeTextAdapter.convert; 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()) { - if (!source.hasPermission(perm)) { - return false; + Set permissions = command.getCondition().as(PermissionCondition.class) + .map(PermissionCondition::getPermissions) + .orElseGet(Collections::emptySet); + for (String perm : permissions) { + if (source.hasPermission(perm)) { + return true; } } - return true; + return false; } @Override public Optional getShortDescription(CommandSource source) { - String description = command.getDescription().getDescription(); - if (description != null && !description.isEmpty()) { - return Optional.of(Text.of(description)); - } - return Optional.empty(); + return Optional.of(command.getDescription()) + .map(SpongeTextAdapter::convert); } @Override public Optional getHelp(CommandSource source) { - String help = command.getDescription().getHelp(); - if (help != null && !help.isEmpty()) { - return Optional.of(Text.of(help)); - } - return Optional.empty(); + return Optional.of(command.getFullHelp()) + .map(SpongeTextAdapter::convert); } @Override public Text getUsage(CommandSource source) { - return Text.of(command.getDescription().getUsage()); + return convert(command.getUsage()); } } 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..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,9 @@ 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; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; @@ -89,6 +92,11 @@ public class SpongeCommandSender implements Actor { sendColorized(msg, TextColors.RED); } + @Override + public void print(Component component) { + TextAdapter.sendComponent(sender, WorldEditText.format(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/SpongePlatform.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java index 774347645..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 @@ -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; @@ -28,11 +29,12 @@ 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.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; @@ -41,6 +43,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; @@ -48,7 +51,7 @@ 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 { @@ -68,6 +71,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(); @@ -122,24 +131,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(); + return CommandUtil.fixSuggestions(arguments, 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()); } } 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..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,12 +31,15 @@ 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; 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; @@ -149,6 +152,11 @@ public class SpongePlayer extends AbstractPlayerActor { sendColorized(msg, TextColors.RED); } + @Override + public void print(Component component) { + TextAdapter.sendComponent(player, WorldEditText.format(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))); @@ -196,6 +204,16 @@ public class SpongePlayer extends AbstractPlayerActor { gameMode.getId()).get()); } + @Override + public boolean isAllowedToFly() { + return player.get(Keys.CAN_FLY).orElse(super.isAllowedToFly()); + } + + @Override + public void setFlying(boolean flying) { + player.offer(Keys.IS_FLYING, flying); + } + @Override public > void sendFakeBlock(BlockVector3 pos, B block) { org.spongepowered.api.world.Location loc = player.getWorld().getLocation(pos.getX(), pos.getY(), pos.getZ()); 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 new file mode 100644 index 000000000..4e7b5c2fb --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeTextAdapter.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.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; +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)); + } + + private SpongeTextAdapter() { + } +} 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..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 @@ -57,8 +57,10 @@ 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.Locale; import java.util.Map; import java.util.Optional; @@ -116,6 +118,17 @@ 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(); + } + @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 98bcb95e4..bca15665b 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; @@ -51,6 +53,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; @@ -61,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; @@ -133,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(); @@ -202,6 +212,22 @@ public class SpongeWorldEdit { return this.spongeAdapter; } + @Listener + public void onPlayerItemInteract(InteractItemEvent.Secondary 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) { @@ -242,26 +268,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); } } } 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. 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 052f19683..76688f766 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 @@ -128,5 +128,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); } }